feat: Ajout de la gestion des utilisateurs et optimisation du chargement des données

Cette mise à jour introduit la gestion complète des utilisateurs (création, mise à jour, suppression) via des Cloud Functions et optimise de manière significative le chargement des données dans toute l'application.

**Features :**
- **Gestion des utilisateurs (Backend & Frontend) :**
    - Ajout des Cloud Functions `getUser`, `updateUser` et `deleteUser` pour gérer les utilisateurs de manière sécurisée, en respectant les permissions des rôles.
    - L'authentification passe désormais par `onCall` pour plus de sécurité.
- **Optimisation du chargement des données :**
    - Introduction de nouvelles Cloud Functions `getEquipmentsByIds` et `getContainersByIds` pour récupérer uniquement les documents nécessaires, réduisant ainsi la charge sur le client et Firestore.
    - Les fournisseurs (`EquipmentProvider`, `ContainerProvider`) ont été refactorisés pour utiliser un chargement à la demande (`ensureLoaded`) et mettre en cache les données récupérées.
    - Les écrans de détails et de préparation d'événements n'utilisent plus de `Stream` globaux, mais chargent les équipements et boites spécifiques via ces nouvelles fonctions, améliorant considérablement les performances.

**Refactorisation et Améliorations :**
- **Backend (Cloud Functions) :**
    - Le service de vérification de disponibilité (`checkEquipmentAvailability`) est désormais une Cloud Function, déplaçant la logique métier côté serveur.
    - La récupération des données (utilisateurs, événements, alertes) a été centralisée derrière des Cloud Functions, remplaçant les appels directs à Firestore depuis le client.
    - Amélioration de la sérialisation des données (timestamps, références) dans les réponses des fonctions.
- **Frontend (Flutter) :**
    - `LocalUserProvider` charge désormais les informations de l'utilisateur connecté via la fonction `getCurrentUser`, incluant son rôle et ses permissions en un seul appel.
    - `AlertProvider` utilise des fonctions pour charger et manipuler les alertes, abandonnant le `Stream` Firestore.
    - `EventAvailabilityService` utilise maintenant la Cloud Function `checkEquipmentAvailability` au lieu d'une logique client complexe.
    - Correction de la gestion des références de rôles (`roles/ADMIN`) et des `DocumentReference` pour les utilisateurs dans l'ensemble de l'application.
    - Le service d'export ICS (`IcsExportService`) a été simplifié, partant du principe que les données nécessaires (utilisateurs, options) sont déjà chargées dans l'application.
This commit is contained in:
ElPoyo
2026-01-13 01:40:28 +01:00
parent f38d75362c
commit 2bcd1ca4c3
16 changed files with 916 additions and 374 deletions

View File

@@ -15,6 +15,11 @@ class EquipmentProvider extends ChangeNotifier {
String? _selectedModel;
String _searchQuery = '';
bool _isLoading = false;
bool _isInitialized = false; // Flag pour savoir si les équipements ont été chargés
// Constructeur - Ne charge PAS automatiquement
// Les équipements seront chargés à la demande (page de gestion ou via getEquipmentsByIds)
EquipmentProvider();
// Getters
List<EquipmentModel> get equipment => _filteredEquipment;
@@ -25,8 +30,19 @@ class EquipmentProvider extends ChangeNotifier {
String? get selectedModel => _selectedModel;
String get searchQuery => _searchQuery;
bool get isLoading => _isLoading;
bool get isInitialized => _isInitialized;
/// Charger tous les équipements via l'API
/// S'assure que les équipements sont chargés (charge si nécessaire)
Future<void> ensureLoaded() async {
if (_isInitialized || _isLoading) {
print('[EquipmentProvider] Equipment already loaded or loading, skipping...');
return;
}
print('[EquipmentProvider] Equipment not loaded, loading now...');
await loadEquipments();
}
/// Charger tous les équipements via l'API (utilisé par la page de gestion)
Future<void> loadEquipments() async {
print('[EquipmentProvider] Starting to load equipments...');
_isLoading = true;
@@ -45,6 +61,8 @@ class EquipmentProvider extends ChangeNotifier {
// Extraire les modèles et marques uniques
_extractUniqueValues();
_isInitialized = true;
_isLoading = false;
notifyListeners();
print('[EquipmentProvider] Equipment loading complete');
@@ -56,6 +74,70 @@ class EquipmentProvider extends ChangeNotifier {
}
}
/// Charge plusieurs équipements par leurs IDs (optimisé pour les détails d'événement)
Future<List<EquipmentModel>> getEquipmentsByIds(List<String> equipmentIds) async {
if (equipmentIds.isEmpty) return [];
print('[EquipmentProvider] Loading ${equipmentIds.length} equipments by IDs...');
try {
// Vérifier d'abord le cache local
final cachedEquipments = <EquipmentModel>[];
final missingIds = <String>[];
for (final id in equipmentIds) {
final cached = _equipment.firstWhere(
(eq) => eq.id == id,
orElse: () => EquipmentModel(
id: '',
name: '',
category: EquipmentCategory.other,
status: EquipmentStatus.available,
parentBoxIds: [],
maintenanceIds: [],
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
);
if (cached.id.isNotEmpty) {
cachedEquipments.add(cached);
} else {
missingIds.add(id);
}
}
print('[EquipmentProvider] Found ${cachedEquipments.length} in cache, ${missingIds.length} missing');
// Si tous sont en cache, retourner directement
if (missingIds.isEmpty) {
return cachedEquipments;
}
// Charger les manquants depuis l'API
final equipmentsData = await _dataService.getEquipmentsByIds(missingIds);
final loadedEquipments = equipmentsData.map((data) {
return EquipmentModel.fromMap(data, data['id'] as String);
}).toList();
// Ajouter au cache
for (final eq in loadedEquipments) {
if (!_equipment.any((e) => e.id == eq.id)) {
_equipment.add(eq);
}
}
print('[EquipmentProvider] Loaded ${loadedEquipments.length} equipments from API');
// Retourner tous les équipements (cache + chargés)
return [...cachedEquipments, ...loadedEquipments];
} catch (e) {
print('[EquipmentProvider] Error loading equipments by IDs: $e');
rethrow;
}
}
/// Extraire modèles et marques uniques
void _extractUniqueValues() {
final modelSet = <String>{};