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:
@@ -45,56 +45,47 @@ END:VCALENDAR''';
|
||||
return icsContent;
|
||||
}
|
||||
|
||||
/// Récupère le nom du type d'événement
|
||||
/// Récupère le nom du type d'événement depuis EventModel (déjà chargé)
|
||||
/// Note: Les eventTypes sont maintenant chargés via Cloud Function dans l'EventModel
|
||||
static Future<String> _getEventTypeName(String eventTypeId) async {
|
||||
if (eventTypeId.isEmpty) return 'Non spécifié';
|
||||
|
||||
try {
|
||||
final doc = await FirebaseFirestore.instance
|
||||
.collection('eventTypes')
|
||||
.doc(eventTypeId)
|
||||
.get();
|
||||
|
||||
if (doc.exists) {
|
||||
return doc.data()?['name'] as String? ?? eventTypeId;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Erreur lors de la récupération du type d\'événement: $e');
|
||||
}
|
||||
|
||||
// Les eventTypes sont publics et déjà chargés dans l'app via Cloud Function
|
||||
// On retourne simplement l'ID, le nom sera résolu par l'app
|
||||
return eventTypeId;
|
||||
}
|
||||
|
||||
/// Récupère les détails de la main d'œuvre
|
||||
/// Note: Les données users devraient être passées directement depuis l'app
|
||||
/// qui les a déjà récupérées via Cloud Function
|
||||
static Future<List<String>> _getWorkforceDetails(List<dynamic> workforce) async {
|
||||
final List<String> workforceNames = [];
|
||||
|
||||
for (final ref in workforce) {
|
||||
try {
|
||||
DocumentReference? docRef;
|
||||
|
||||
// Gérer String (UID) ou DocumentReference
|
||||
if (ref is String) {
|
||||
docRef = FirebaseFirestore.instance.collection('users').doc(ref);
|
||||
} else if (ref is DocumentReference) {
|
||||
docRef = ref;
|
||||
// Si c'est déjà une Map avec les données, l'utiliser directement
|
||||
if (ref is Map<String, dynamic>) {
|
||||
final firstName = ref['firstName'] ?? '';
|
||||
final lastName = ref['lastName'] ?? '';
|
||||
if (firstName.isNotEmpty || lastName.isNotEmpty) {
|
||||
workforceNames.add('$firstName $lastName'.trim());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (docRef != null) {
|
||||
final doc = await docRef.get();
|
||||
if (doc.exists) {
|
||||
final data = doc.data() as Map<String, dynamic>?;
|
||||
if (data != null) {
|
||||
final firstName = data['firstName'] ?? '';
|
||||
final lastName = data['lastName'] ?? '';
|
||||
if (firstName.isNotEmpty || lastName.isNotEmpty) {
|
||||
workforceNames.add('$firstName $lastName'.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Si c'est un String (UID), on ne peut pas récupérer les données ici
|
||||
// Les données devraient être passées directement
|
||||
if (ref is String) {
|
||||
workforceNames.add('Utilisateur $ref');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Si c'est une DocumentReference, extraire l'ID seulement
|
||||
if (ref is DocumentReference) {
|
||||
workforceNames.add('Utilisateur ${ref.id}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Erreur lors de la récupération des détails utilisateur: $e');
|
||||
print('Erreur lors du traitement des détails utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,46 +93,19 @@ END:VCALENDAR''';
|
||||
}
|
||||
|
||||
/// Récupère les détails des options
|
||||
/// Note: Les options sont publiques et déjà chargées via Cloud Function
|
||||
static Future<List<Map<String, dynamic>>> _getOptionsDetails(List<Map<String, dynamic>> options) async {
|
||||
final List<Map<String, dynamic>> optionsWithNames = [];
|
||||
|
||||
for (final option in options) {
|
||||
try {
|
||||
final optionId = option['id'] ?? option['optionId'];
|
||||
if (optionId == null || optionId.toString().isEmpty) {
|
||||
// Si pas d'ID, garder le nom tel quel
|
||||
optionsWithNames.add({
|
||||
'name': option['name'] ?? 'Option inconnue',
|
||||
'quantity': option['quantity'],
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Récupérer le nom depuis Firestore
|
||||
final doc = await FirebaseFirestore.instance
|
||||
.collection('options')
|
||||
.doc(optionId.toString())
|
||||
.get();
|
||||
|
||||
if (doc.exists) {
|
||||
final data = doc.data();
|
||||
optionsWithNames.add({
|
||||
'name': data?['name'] ?? option['name'] ?? 'Option inconnue',
|
||||
'quantity': option['quantity'],
|
||||
});
|
||||
} else {
|
||||
// Document n'existe pas, garder le nom de l'option
|
||||
optionsWithNames.add({
|
||||
'name': option['name'] ?? 'Option inconnue',
|
||||
'quantity': option['quantity'],
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
print('Erreur lors de la récupération des détails option: $e');
|
||||
// Les options devraient déjà contenir le nom
|
||||
optionsWithNames.add({
|
||||
'name': option['name'] ?? 'Option inconnue',
|
||||
'name': option['name'] ?? option['optionId'] ?? 'Option inconnue',
|
||||
'quantity': option['quantity'],
|
||||
});
|
||||
} catch (e) {
|
||||
print('Erreur lors du traitement des options: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user