- Mise à jour VERSION vers 3.3.4 - Optimisations et révisions architecture API (deploy-api.sh, scripts de migration) - Ajout documentation Stripe Tap to Pay complète - Migration vers polices Inter Variable pour Flutter - Optimisations build Android et nettoyage fichiers temporaires - Amélioration système de déploiement avec gestion backups - Ajout scripts CRON et migrations base de données 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
207 lines
6.2 KiB
Dart
207 lines
6.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:geosector_app/presentation/widgets/dashboard_layout.dart';
|
|
import 'package:geosector_app/presentation/widgets/badged_navigation_destination.dart';
|
|
import 'package:geosector_app/app.dart';
|
|
import 'dart:math' as math;
|
|
|
|
/// Class pour dessiner les petits points blancs sur le fond
|
|
class DotsPainter extends CustomPainter {
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final paint = Paint()
|
|
..color = Colors.white.withValues(alpha: 0.5)
|
|
..style = PaintingStyle.fill;
|
|
|
|
final random = math.Random(42); // Seed fixe pour consistance
|
|
final numberOfDots = (size.width * size.height) ~/ 1500;
|
|
|
|
for (int i = 0; i < numberOfDots; i++) {
|
|
final x = random.nextDouble() * size.width;
|
|
final y = random.nextDouble() * size.height;
|
|
final radius = 1.0 + random.nextDouble() * 2.0;
|
|
canvas.drawCircle(Offset(x, y), radius, paint);
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
|
}
|
|
|
|
/// Scaffold partagé pour toutes les pages d'administration
|
|
/// Fournit le fond dégradé et la navigation commune
|
|
class AdminScaffold extends StatelessWidget {
|
|
/// Le contenu de la page
|
|
final Widget body;
|
|
|
|
/// L'index de navigation sélectionné
|
|
final int selectedIndex;
|
|
|
|
/// Le titre de la page
|
|
final String pageTitle;
|
|
|
|
/// Callback optionnel pour gérer la navigation personnalisée
|
|
final Function(int)? onDestinationSelected;
|
|
|
|
const AdminScaffold({
|
|
super.key,
|
|
required this.body,
|
|
required this.selectedIndex,
|
|
required this.pageTitle,
|
|
this.onDestinationSelected,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final currentUser = userRepository.getCurrentUser();
|
|
final size = MediaQuery.of(context).size;
|
|
final isMobile = size.width <= 900;
|
|
|
|
return Stack(
|
|
children: [
|
|
// Fond dégradé avec petits points blancs
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Colors.white, Colors.red.shade300],
|
|
),
|
|
),
|
|
child: CustomPaint(
|
|
painter: DotsPainter(),
|
|
child: const SizedBox(width: double.infinity, height: double.infinity),
|
|
),
|
|
),
|
|
|
|
// Contenu de la page avec navigation
|
|
DashboardLayout(
|
|
key: ValueKey('dashboard_layout_$selectedIndex'),
|
|
title: 'Tableau de bord Administration',
|
|
selectedIndex: selectedIndex,
|
|
onDestinationSelected: onDestinationSelected ?? (index) {
|
|
// Navigation par défaut si pas de callback personnalisé
|
|
AdminNavigationHelper.navigateToIndex(context, index);
|
|
},
|
|
destinations: AdminNavigationHelper.getDestinations(
|
|
currentUser: currentUser,
|
|
isMobile: isMobile,
|
|
),
|
|
isAdmin: true,
|
|
body: body,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Helper pour centraliser la logique de navigation admin
|
|
class AdminNavigationHelper {
|
|
/// Obtenir la liste des destinations de navigation selon le rôle et le device
|
|
static List<NavigationDestination> getDestinations({
|
|
required dynamic currentUser,
|
|
required bool isMobile,
|
|
}) {
|
|
final destinations = <NavigationDestination>[
|
|
// Pages de base toujours visibles
|
|
const NavigationDestination(
|
|
icon: Icon(Icons.dashboard_outlined),
|
|
selectedIcon: Icon(Icons.dashboard),
|
|
label: 'Tableau de bord',
|
|
),
|
|
const NavigationDestination(
|
|
icon: Icon(Icons.bar_chart_outlined),
|
|
selectedIcon: Icon(Icons.bar_chart),
|
|
label: 'Statistiques',
|
|
),
|
|
const NavigationDestination(
|
|
icon: Icon(Icons.history_outlined),
|
|
selectedIcon: Icon(Icons.history),
|
|
label: 'Historique',
|
|
),
|
|
createBadgedNavigationDestination(
|
|
icon: const Icon(Icons.chat_outlined),
|
|
selectedIcon: const Icon(Icons.chat),
|
|
label: 'Messages',
|
|
showBadge: true,
|
|
),
|
|
const NavigationDestination(
|
|
icon: Icon(Icons.map_outlined),
|
|
selectedIcon: Icon(Icons.map),
|
|
label: 'Carte',
|
|
),
|
|
];
|
|
|
|
// Ajouter les pages admin (role 2) seulement sur desktop
|
|
if (currentUser?.role == 2 && !isMobile) {
|
|
destinations.addAll([
|
|
const NavigationDestination(
|
|
icon: Icon(Icons.business_outlined),
|
|
selectedIcon: Icon(Icons.business),
|
|
label: 'Amicale & membres',
|
|
),
|
|
const NavigationDestination(
|
|
icon: Icon(Icons.calendar_today_outlined),
|
|
selectedIcon: Icon(Icons.calendar_today),
|
|
label: 'Opérations',
|
|
),
|
|
]);
|
|
}
|
|
|
|
return destinations;
|
|
}
|
|
|
|
/// Naviguer vers une page selon l'index
|
|
static void navigateToIndex(BuildContext context, int index) {
|
|
switch (index) {
|
|
case 0:
|
|
context.go('/admin');
|
|
break;
|
|
case 1:
|
|
context.go('/admin/statistics');
|
|
break;
|
|
case 2:
|
|
context.go('/admin/history');
|
|
break;
|
|
case 3:
|
|
context.go('/admin/messages');
|
|
break;
|
|
case 4:
|
|
context.go('/admin/map');
|
|
break;
|
|
case 5:
|
|
context.go('/admin/amicale');
|
|
break;
|
|
case 6:
|
|
context.go('/admin/operations');
|
|
break;
|
|
default:
|
|
context.go('/admin');
|
|
}
|
|
}
|
|
|
|
/// Obtenir l'index selon la route actuelle
|
|
static int getIndexFromRoute(String route) {
|
|
if (route.contains('/statistics')) return 1;
|
|
if (route.contains('/history')) return 2;
|
|
if (route.contains('/messages')) return 3;
|
|
if (route.contains('/map')) return 4;
|
|
if (route.contains('/amicale')) return 5;
|
|
if (route.contains('/operations')) return 6;
|
|
return 0; // Dashboard par défaut
|
|
}
|
|
|
|
/// Obtenir le nom de la page selon l'index
|
|
static String getPageNameFromIndex(int index) {
|
|
switch (index) {
|
|
case 0: return 'dashboard';
|
|
case 1: return 'statistics';
|
|
case 2: return 'history';
|
|
case 3: return 'messages';
|
|
case 4: return 'map';
|
|
case 5: return 'amicale';
|
|
case 6: return 'operations';
|
|
default: return 'dashboard';
|
|
}
|
|
}
|
|
} |