Files
unionflow-mobile-apps/lib/core/navigation/more_page.dart
2026-03-31 09:14:47 +00:00

300 lines
11 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../features/authentication/presentation/bloc/auth_bloc.dart';
import '../../features/authentication/data/models/user_role.dart';
import '../../shared/design_system/unionflow_design_system.dart';
import '../../shared/widgets/core_card.dart';
import '../../shared/widgets/mini_avatar.dart';
import '../../features/admin/presentation/pages/user_management_page.dart';
import '../../features/settings/presentation/pages/system_settings_page.dart';
import '../../features/backup/presentation/pages/backup_page.dart';
import '../../features/logs/presentation/pages/logs_page.dart';
import '../../features/reports/presentation/pages/reports_page_wrapper.dart';
import '../../features/epargne/presentation/pages/epargne_page.dart';
import '../../features/contributions/presentation/pages/contributions_page_wrapper.dart';
import '../../features/adhesions/presentation/pages/adhesions_page_wrapper.dart';
import '../../features/solidarity/presentation/pages/demandes_aide_page_wrapper.dart';
import '../../features/organizations/presentation/pages/organizations_page_wrapper.dart';
import '../../features/profile/presentation/pages/profile_page_wrapper.dart';
/// Page "Plus" avec les fonctions avancées selon le rôle
class MorePage extends StatelessWidget {
const MorePage({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is! AuthAuthenticated) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
backgroundColor: AppColors.lightBackground,
appBar: const UFAppBar(
title: 'PLUS',
automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildUserProfile(context, state),
const SizedBox(height: SpacingTokens.md),
..._buildRoleBasedOptions(context, state),
const SizedBox(height: SpacingTokens.md),
..._buildCommonOptions(context),
],
),
),
);
},
);
}
Widget _buildUserProfile(BuildContext context, AuthAuthenticated state) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final textColor = isDark ? AppColors.textPrimaryDark : AppColors.textPrimaryLight;
final roleColor = isDark ? AppColors.brandGreenLight : AppColors.primaryGreen;
return CoreCard(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ProfilePageWrapper()),
),
child: Row(
children: [
MiniAvatar(
fallbackText: state.user.firstName.isNotEmpty
? state.user.firstName[0].toUpperCase()
: 'U',
size: 40,
imageUrl: state.user.avatar,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${state.user.firstName} ${state.user.lastName}',
style: AppTypography.actionText.copyWith(color: textColor),
),
Text(
state.effectiveRole.displayName.toUpperCase(),
style: AppTypography.badgeText.copyWith(
color: roleColor,
fontWeight: FontWeight.bold,
),
),
],
),
),
Icon(Icons.chevron_right,
color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight,
size: 16),
],
),
);
}
List<Widget> _buildRoleBasedOptions(BuildContext context, AuthAuthenticated state) {
final options = <Widget>[];
if (state.effectiveRole == UserRole.superAdmin) {
options.addAll([
_buildSectionTitle(context, 'Administration Système'),
_buildOptionTile(context,
icon: Icons.people,
title: 'Gestion des utilisateurs',
subtitle: 'Utilisateurs Keycloak et rôles',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const UserManagementPage())),
),
_buildOptionTile(context,
icon: Icons.settings,
title: 'Paramètres Système',
subtitle: 'Configuration globale',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const SystemSettingsPage())),
),
_buildOptionTile(context,
icon: Icons.backup,
title: 'Sauvegarde & Restauration',
subtitle: 'Gestion des sauvegardes',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const BackupPage())),
),
_buildOptionTile(context,
icon: Icons.article,
title: 'Logs & Monitoring',
subtitle: 'Surveillance et journaux',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const LogsPage())),
),
]);
}
if (state.effectiveRole == UserRole.orgAdmin ||
state.effectiveRole == UserRole.superAdmin) {
options.addAll([
_buildSectionTitle(context, 'Administration'),
_buildOptionTile(context,
icon: Icons.business,
title: 'Gestion des Organisations',
subtitle: 'Créer et gérer les organisations',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const OrganizationsPageWrapper())),
),
_buildSectionTitle(context, 'Workflow Financier'),
_buildOptionTile(context,
icon: Icons.pending_actions,
title: 'Approbations en attente',
subtitle: 'Valider les transactions financières',
onTap: () => Navigator.pushNamed(context, '/approvals'),
),
_buildOptionTile(context,
icon: Icons.account_balance_wallet,
title: 'Gestion des Budgets',
subtitle: 'Créer et suivre les budgets',
onTap: () => Navigator.pushNamed(context, '/budgets'),
),
_buildSectionTitle(context, 'Communication'),
_buildOptionTile(context,
icon: Icons.message,
title: 'Messages & Broadcast',
subtitle: 'Communiquer avec les membres',
onTap: () => Navigator.pushNamed(context, '/messages'),
),
_buildSectionTitle(context, 'Rapports & Analytics'),
_buildOptionTile(context,
icon: Icons.assessment,
title: 'Rapports & Analytics',
subtitle: 'Statistiques détaillées',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ReportsPageWrapper())),
),
]);
}
if (state.effectiveRole == UserRole.moderator) {
options.addAll([
_buildSectionTitle(context, 'Communication'),
_buildOptionTile(context,
icon: Icons.message,
title: 'Messages aux membres',
subtitle: 'Communiquer avec les membres',
onTap: () => Navigator.pushNamed(context, '/messages'),
),
]);
}
return options;
}
List<Widget> _buildCommonOptions(BuildContext context) {
return [
_buildSectionTitle(context, 'Général'),
_buildOptionTile(context,
icon: Icons.payment,
title: 'Cotisations',
subtitle: 'Gérer les cotisations',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const CotisationsPageWrapper())),
),
_buildOptionTile(context,
icon: Icons.how_to_reg,
title: 'Demandes d\'adhésion',
subtitle: 'Demandes d\'adhésion à une organisation',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const AdhesionsPageWrapper())),
),
_buildOptionTile(context,
icon: Icons.volunteer_activism,
title: 'Demandes d\'aide',
subtitle: 'Solidarité demandes d\'aide',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const DemandesAidePageWrapper())),
),
_buildOptionTile(context,
icon: Icons.savings_outlined,
title: 'Comptes épargne',
subtitle: 'Mutuelle épargne dépôts (LCB-FT)',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const EpargnePage())),
),
];
}
Widget _buildSectionTitle(BuildContext context, String title) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return Padding(
padding: const EdgeInsets.only(top: 16, bottom: 6, left: 4),
child: Text(
title.toUpperCase(),
style: AppTypography.subtitleSmall.copyWith(
fontWeight: FontWeight.bold,
letterSpacing: 1.1,
color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight,
),
),
);
}
Widget _buildOptionTile(
BuildContext context, {
required IconData icon,
required String title,
required String subtitle,
required VoidCallback onTap,
Color? accentColor,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final accent = accentColor ?? AppColors.primaryGreen;
final titleColor = accentColor != null
? accentColor
: (isDark ? AppColors.textPrimaryDark : AppColors.textPrimaryLight);
final subtitleColor =
isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight;
final chevronColor =
isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight;
return CoreCard(
margin: const EdgeInsets.only(bottom: 8),
onTap: onTap,
child: Row(
children: [
Container(
padding: const EdgeInsets.all(7),
decoration: BoxDecoration(
color: accent.withOpacity(isDark ? 0.2 : 0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: accent, size: 18),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: AppTypography.actionText.copyWith(color: titleColor),
),
Text(
subtitle,
style: AppTypography.subtitleSmall.copyWith(color: subtitleColor),
),
],
),
),
Icon(Icons.chevron_right, color: chevronColor, size: 16),
],
),
);
}
}