feat: Gestion des secteurs et migration v3.0.4+304

- Ajout système complet de gestion des secteurs avec contours géographiques
- Import des contours départementaux depuis GeoJSON
- API REST pour la gestion des secteurs (/api/sectors)
- Service de géolocalisation pour déterminer les secteurs
- Migration base de données avec tables x_departements_contours et sectors_adresses
- Interface Flutter pour visualisation et gestion des secteurs
- Ajout thème sombre dans l'application
- Corrections diverses et optimisations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-08-07 11:01:45 +02:00
parent 3bbc599ab4
commit 1018b86537
620 changed files with 120502 additions and 91396 deletions

57
app/lib/presentation/admin/admin_dashboard_page.dart Normal file → Executable file
View File

@@ -47,8 +47,7 @@ class AdminDashboardPage extends StatefulWidget {
class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBindingObserver {
int _selectedIndex = 0;
// Liste des pages à afficher
late final List<Widget> _pages;
// Pages seront construites dynamiquement dans build()
// Référence à la boîte Hive pour les paramètres
late Box _settingsBox;
@@ -138,6 +137,8 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
List<NavigationDestination> _buildNavigationDestinations() {
final destinations = <NavigationDestination>[];
final currentUser = userRepository.getCurrentUser();
final size = MediaQuery.of(context).size;
final isMobile = size.width <= 900;
// Ajouter les éléments de base
for (final item in _baseNavigationItems) {
@@ -153,6 +154,12 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
// Ajouter les éléments admin si l'utilisateur a le rôle requis
if (currentUser?.role == 2) {
for (final item in _adminNavigationItems) {
// En mobile, exclure "Amicale & membres" et "Opérations"
if (isMobile &&
(item.label == 'Amicale & membres' || item.label == 'Opérations')) {
continue;
}
if (item.requiredRole == null || item.requiredRole == 2) {
destinations.add(
NavigationDestination(
@@ -172,6 +179,8 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
List<Widget> _buildPages() {
final pages = <Widget>[];
final currentUser = userRepository.getCurrentUser();
final size = MediaQuery.of(context).size;
final isMobile = size.width <= 900;
// Ajouter les pages de base
for (final item in _baseNavigationItems) {
@@ -181,6 +190,12 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
// Ajouter les pages admin si l'utilisateur a le rôle requis
if (currentUser?.role == 2) {
for (final item in _adminNavigationItems) {
// En mobile, exclure "Amicale & membres" et "Opérations"
if (isMobile &&
(item.label == 'Amicale & membres' || item.label == 'Opérations')) {
continue;
}
if (item.requiredRole == null || item.requiredRole == 2) {
pages.add(_buildPage(item.pageType));
}
@@ -208,8 +223,7 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
}
userRepository.addListener(_handleUserRepositoryChanges);
// Initialiser les pages et les destinations
_pages = _buildPages();
// Les pages seront construites dynamiquement dans build()
// Initialiser et charger les paramètres
_initSettings();
@@ -257,19 +271,11 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
if (savedIndex != null && savedIndex is int) {
debugPrint('Index sauvegardé trouvé: $savedIndex');
// S'assurer que l'index est dans les limites valides
if (savedIndex >= 0 && savedIndex < _pages.length) {
setState(() {
_selectedIndex = savedIndex;
});
debugPrint('Index sauvegardé valide, utilisé: $_selectedIndex');
} else {
debugPrint(
'Index sauvegardé invalide ($savedIndex), utilisation de l\'index par défaut: 0',
);
// Réinitialiser l'index sauvegardé à 0 si invalide
_settingsBox.put('adminSelectedPageIndex', 0);
}
// La validation de l'index sera faite dans build()
setState(() {
_selectedIndex = savedIndex;
});
debugPrint('Index sauvegardé utilisé: $_selectedIndex');
} else {
debugPrint(
'Aucun index sauvegardé trouvé, utilisation de l\'index par défaut: 0',
@@ -292,6 +298,19 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
@override
Widget build(BuildContext context) {
// Construire les pages et destinations dynamiquement
final pages = _buildPages();
final destinations = _buildNavigationDestinations();
// Valider et ajuster l'index si nécessaire
if (_selectedIndex >= pages.length) {
_selectedIndex = 0;
// Sauvegarder le nouvel index
WidgetsBinding.instance.addPostFrameCallback((_) {
_saveSettings();
});
}
return Stack(
children: [
// Fond dégradé avec petits points blancs
@@ -318,10 +337,10 @@ class _AdminDashboardPageState extends State<AdminDashboardPage> with WidgetsBin
_saveSettings(); // Sauvegarder l'index de page sélectionné
});
},
destinations: _buildNavigationDestinations(),
destinations: destinations,
showNewPassageButton: false,
isAdmin: true,
body: _pages[_selectedIndex],
body: pages[_selectedIndex],
),
],
);