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:
@@ -84,16 +84,6 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Met à jour un utilisateur
|
||||
Future<void> updateUser(String userId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
final requestData = {'userId': userId, ...data};
|
||||
await _apiService.call('updateUser', requestData);
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la mise à jour de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Met à jour un événement
|
||||
Future<void> updateEvent(String eventId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
@@ -271,6 +261,28 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère plusieurs équipements par leurs IDs
|
||||
Future<List<Map<String, dynamic>>> getEquipmentsByIds(List<String> equipmentIds) async {
|
||||
try {
|
||||
if (equipmentIds.isEmpty) return [];
|
||||
|
||||
print('[DataService] Getting equipments by IDs: ${equipmentIds.length} items');
|
||||
final result = await _apiService.call('getEquipmentsByIds', {
|
||||
'equipmentIds': equipmentIds,
|
||||
});
|
||||
final equipments = result['equipments'] as List<dynamic>?;
|
||||
if (equipments == null) {
|
||||
print('[DataService] No equipments in result');
|
||||
return [];
|
||||
}
|
||||
print('[DataService] Found ${equipments.length} equipments by IDs');
|
||||
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[DataService] Error getting equipments by IDs: $e');
|
||||
throw Exception('Erreur lors de la récupération des équipements: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère tous les conteneurs
|
||||
Future<List<Map<String, dynamic>>> getContainers() async {
|
||||
try {
|
||||
@@ -283,6 +295,28 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère plusieurs conteneurs par leurs IDs
|
||||
Future<List<Map<String, dynamic>>> getContainersByIds(List<String> containerIds) async {
|
||||
try {
|
||||
if (containerIds.isEmpty) return [];
|
||||
|
||||
print('[DataService] Getting containers by IDs: ${containerIds.length} items');
|
||||
final result = await _apiService.call('getContainersByIds', {
|
||||
'containerIds': containerIds,
|
||||
});
|
||||
final containers = result['containers'] as List<dynamic>?;
|
||||
if (containers == null) {
|
||||
print('[DataService] No containers in result');
|
||||
return [];
|
||||
}
|
||||
print('[DataService] Found ${containers.length} containers by IDs');
|
||||
return containers.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[DataService] Error getting containers by IDs: $e');
|
||||
throw Exception('Erreur lors de la récupération des conteneurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les maintenances (optionnellement filtrées par équipement)
|
||||
Future<List<Map<String, dynamic>>> getMaintenances({String? equipmentId}) async {
|
||||
try {
|
||||
@@ -298,29 +332,6 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les alertes
|
||||
Future<List<Map<String, dynamic>>> getAlerts() async {
|
||||
try {
|
||||
final result = await _apiService.call('getAlerts', {});
|
||||
final alerts = result['alerts'] as List<dynamic>?;
|
||||
if (alerts == null) return [];
|
||||
return alerts.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des alertes: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les utilisateurs (filtrés selon permissions)
|
||||
Future<List<Map<String, dynamic>>> getUsers() async {
|
||||
try {
|
||||
final result = await _apiService.call('getUsers', {});
|
||||
final users = result['users'] as List<dynamic>?;
|
||||
if (users == null) return [];
|
||||
return users.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des utilisateurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les containers contenant un équipement spécifique
|
||||
Future<List<Map<String, dynamic>>> getContainersByEquipment(String equipmentId) async {
|
||||
@@ -335,5 +346,138 @@ class DataService {
|
||||
throw Exception('Erreur lors de la récupération des containers pour l\'équipement: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// USER - Current User
|
||||
// ============================================================================
|
||||
|
||||
/// Récupère l'utilisateur actuellement authentifié avec son rôle
|
||||
Future<Map<String, dynamic>> getCurrentUser() async {
|
||||
try {
|
||||
print('[DataService] Calling getCurrentUser API...');
|
||||
final result = await _apiService.call('getCurrentUser', {});
|
||||
print('[DataService] Current user loaded successfully');
|
||||
return result['user'] as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
print('[DataService] Error getting current user: $e');
|
||||
throw Exception('Erreur lors de la récupération de l\'utilisateur actuel: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ALERTS
|
||||
// ============================================================================
|
||||
|
||||
/// Récupère toutes les alertes
|
||||
Future<List<Map<String, dynamic>>> getAlerts() async {
|
||||
try {
|
||||
final result = await _apiService.call('getAlerts', {});
|
||||
final alerts = result['alerts'] as List<dynamic>?;
|
||||
if (alerts == null) return [];
|
||||
return alerts.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des alertes: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Marque une alerte comme lue
|
||||
Future<void> markAlertAsRead(String alertId) async {
|
||||
try {
|
||||
await _apiService.call('markAlertAsRead', {'alertId': alertId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors du marquage de l\'alerte comme lue: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Supprime une alerte
|
||||
Future<void> deleteAlert(String alertId) async {
|
||||
try {
|
||||
await _apiService.call('deleteAlert', {'alertId': alertId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de l\'alerte: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EQUIPMENT AVAILABILITY
|
||||
// ============================================================================
|
||||
|
||||
/// Vérifie la disponibilité d'un équipement
|
||||
Future<Map<String, dynamic>> checkEquipmentAvailability({
|
||||
required String equipmentId,
|
||||
required DateTime startDate,
|
||||
required DateTime endDate,
|
||||
String? excludeEventId,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _apiService.call('checkEquipmentAvailability', {
|
||||
'equipmentId': equipmentId,
|
||||
'startDate': startDate.toIso8601String(),
|
||||
'endDate': endDate.toIso8601String(),
|
||||
if (excludeEventId != null) 'excludeEventId': excludeEventId,
|
||||
});
|
||||
return result;
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la vérification de disponibilité: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// MAINTENANCES
|
||||
// ============================================================================
|
||||
|
||||
/// Supprime une maintenance
|
||||
Future<void> deleteMaintenance(String maintenanceId) async {
|
||||
try {
|
||||
await _apiService.call('deleteMaintenance', {'maintenanceId': maintenanceId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de la maintenance: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// USERS
|
||||
// ============================================================================
|
||||
|
||||
/// Récupère tous les utilisateurs (selon permissions)
|
||||
Future<List<Map<String, dynamic>>> getUsers() async {
|
||||
try {
|
||||
final result = await _apiService.call('getUsers', {});
|
||||
final users = result['users'] as List<dynamic>?;
|
||||
if (users == null) return [];
|
||||
return users.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des utilisateurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère un utilisateur spécifique
|
||||
Future<Map<String, dynamic>> getUser(String userId) async {
|
||||
try {
|
||||
final result = await _apiService.call('getUser', {'userId': userId});
|
||||
return result['user'] as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Supprime un utilisateur (Auth + Firestore)
|
||||
Future<void> deleteUser(String userId) async {
|
||||
try {
|
||||
await _apiService.call('deleteUser', {'userId': userId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Met à jour un utilisateur
|
||||
Future<void> updateUser(String userId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
final requestData = {'userId': userId, ...data};
|
||||
await _apiService.call('updateUser', requestData);
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la mise à jour de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:em2rp/models/event_model.dart';
|
||||
import 'package:em2rp/models/equipment_model.dart';
|
||||
import 'package:em2rp/models/container_model.dart';
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
import 'package:em2rp/services/data_service.dart';
|
||||
|
||||
/// Type de conflit
|
||||
enum ConflictType {
|
||||
@@ -63,9 +64,16 @@ class AvailabilityConflict {
|
||||
|
||||
/// Service pour vérifier la disponibilité du matériel
|
||||
class EventAvailabilityService {
|
||||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
final DataService _dataService = DataService(apiService);
|
||||
|
||||
/// Vérifie si un équipement est disponible pour une plage de dates
|
||||
/// Helper pour récupérer uniquement la liste d'événements
|
||||
Future<List<Map<String, dynamic>>> _getEventsList() async {
|
||||
final result = await _dataService.getEvents();
|
||||
final events = result['events'] as List<dynamic>? ?? [];
|
||||
return events.map((e) => e as Map<String, dynamic>).toList();
|
||||
}
|
||||
|
||||
/// Vérifie si un équipement est disponible pour une plage de dates via Cloud Function
|
||||
Future<List<AvailabilityConflict>> checkEquipmentAvailability({
|
||||
required String equipmentId,
|
||||
required String equipmentName,
|
||||
@@ -76,59 +84,44 @@ class EventAvailabilityService {
|
||||
final conflicts = <AvailabilityConflict>[];
|
||||
|
||||
try {
|
||||
// Récupérer TOUS les événements (on filtre côté client car arrayContains avec objet ne marche pas)
|
||||
final eventsSnapshot = await _firestore.collection('events').get();
|
||||
// Utiliser la Cloud Function pour vérifier la disponibilité
|
||||
final result = await _dataService.checkEquipmentAvailability(
|
||||
equipmentId: equipmentId,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
excludeEventId: excludeEventId,
|
||||
);
|
||||
|
||||
for (var doc in eventsSnapshot.docs) {
|
||||
if (excludeEventId != null && doc.id == excludeEventId) {
|
||||
continue; // Ignorer l'événement en cours d'édition
|
||||
}
|
||||
final available = result['available'] as bool? ?? true;
|
||||
if (!available) {
|
||||
final conflictsData = result['conflicts'] as List<dynamic>? ?? [];
|
||||
|
||||
try {
|
||||
final data = doc.data();
|
||||
final event = EventModel.fromMap(data, doc.id);
|
||||
// Récupérer les détails des événements en conflit
|
||||
final eventsData = await _getEventsList();
|
||||
|
||||
// Ignorer les événements annulés
|
||||
if (event.status == EventStatus.canceled) {
|
||||
continue;
|
||||
}
|
||||
for (final conflictData in conflictsData) {
|
||||
final conflict = conflictData as Map<String, dynamic>;
|
||||
final eventId = conflict['eventId'] as String;
|
||||
|
||||
// Vérifier si cet événement contient l'équipement recherché
|
||||
final assignedEquipment = event.assignedEquipment.firstWhere(
|
||||
(eq) => eq.equipmentId == equipmentId,
|
||||
orElse: () => EventEquipment(equipmentId: ''),
|
||||
// Trouver l'événement correspondant
|
||||
final eventData = eventsData.firstWhere(
|
||||
(e) => e['id'] == eventId,
|
||||
orElse: () => <String, dynamic>{},
|
||||
);
|
||||
|
||||
// Si l'équipement est assigné à cet événement, il est indisponible
|
||||
// (peu importe le statut de préparation/chargement/retour)
|
||||
if (assignedEquipment.equipmentId.isNotEmpty) {
|
||||
// Calculer les dates réelles avec temps d'installation et démontage
|
||||
final eventRealStartDate = event.startDateTime.subtract(
|
||||
Duration(hours: event.installationTime),
|
||||
);
|
||||
final eventRealEndDate = event.endDateTime.add(
|
||||
Duration(hours: event.disassemblyTime),
|
||||
);
|
||||
|
||||
// Vérifier le chevauchement des dates
|
||||
if (_datesOverlap(startDate, endDate, eventRealStartDate, eventRealEndDate)) {
|
||||
final overlapDays = _calculateOverlapDays(
|
||||
startDate,
|
||||
endDate,
|
||||
eventRealStartDate,
|
||||
eventRealEndDate,
|
||||
);
|
||||
|
||||
if (eventData.isNotEmpty) {
|
||||
try {
|
||||
final event = EventModel.fromMap(eventData, eventId);
|
||||
conflicts.add(AvailabilityConflict(
|
||||
equipmentId: equipmentId,
|
||||
equipmentName: equipmentName,
|
||||
conflictingEvent: event,
|
||||
overlapDays: overlapDays,
|
||||
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
||||
));
|
||||
} catch (e) {
|
||||
print('[EventAvailabilityService] Error creating EventModel: $e');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('[EventAvailabilityService] Error processing event ${doc.id}: $e');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -138,11 +131,6 @@ class EventAvailabilityService {
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
/// Helper pour formater les dates dans les logs
|
||||
String _formatDate(DateTime date) {
|
||||
return '${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year} ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
/// Vérifie la disponibilité pour une liste d'équipements
|
||||
Future<Map<String, List<AvailabilityConflict>>> checkMultipleEquipmentAvailability({
|
||||
required List<String> equipmentIds,
|
||||
@@ -203,16 +191,17 @@ class EventAvailabilityService {
|
||||
int reservedQuantity = 0;
|
||||
|
||||
try {
|
||||
// Récupérer tous les événements (on filtre côté client)
|
||||
final eventsSnapshot = await _firestore.collection('events').get();
|
||||
// Récupérer tous les événements via Cloud Function
|
||||
final eventsData = await _getEventsList();
|
||||
|
||||
for (var doc in eventsSnapshot.docs) {
|
||||
if (excludeEventId != null && doc.id == excludeEventId) {
|
||||
for (var eventData in eventsData) {
|
||||
final eventId = eventData['id'] as String;
|
||||
if (excludeEventId != null && eventId == excludeEventId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
final event = EventModel.fromMap(doc.data(), doc.id);
|
||||
final event = EventModel.fromMap(eventData, eventId);
|
||||
|
||||
// Ignorer les événements annulés
|
||||
if (event.status == EventStatus.canceled) {
|
||||
@@ -241,7 +230,7 @@ class EventAvailabilityService {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('[EventAvailabilityService] Error processing event ${doc.id} for quantity: $e');
|
||||
print('[EventAvailabilityService] Error processing event $eventId for quantity: $e');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -275,13 +264,14 @@ class EventAvailabilityService {
|
||||
// ✅ Ne créer un conflit que si la quantité est VRAIMENT insuffisante
|
||||
if (availableQty < requestedQuantity) {
|
||||
// Trouver les événements qui réservent cette quantité
|
||||
final eventsSnapshot = await _firestore.collection('events').get();
|
||||
final eventsData = await _getEventsList();
|
||||
|
||||
for (var doc in eventsSnapshot.docs) {
|
||||
if (excludeEventId != null && doc.id == excludeEventId) continue;
|
||||
for (var eventData in eventsData) {
|
||||
final eventId = eventData['id'] as String;
|
||||
if (excludeEventId != null && eventId == excludeEventId) continue;
|
||||
|
||||
try {
|
||||
final event = EventModel.fromMap(doc.data(), doc.id);
|
||||
final event = EventModel.fromMap(eventData, eventId);
|
||||
|
||||
if (_datesOverlap(startDate, endDate, event.startDateTime, event.endDateTime)) {
|
||||
final assignedEquipment = event.assignedEquipment.firstWhere(
|
||||
@@ -304,7 +294,7 @@ class EventAvailabilityService {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('[EventAvailabilityService] Error processing event ${doc.id}: $e');
|
||||
print('[EventAvailabilityService] Error processing event $eventId: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,15 +324,16 @@ class EventAvailabilityService {
|
||||
final conflictingChildrenIds = <String>[];
|
||||
|
||||
// Vérifier d'abord si la boîte complète est utilisée
|
||||
final eventsSnapshot = await _firestore.collection('events').get();
|
||||
final eventsData = await _getEventsList();
|
||||
bool isContainerFullyUsed = false;
|
||||
EventModel? containerConflictingEvent;
|
||||
|
||||
for (var doc in eventsSnapshot.docs) {
|
||||
if (excludeEventId != null && doc.id == excludeEventId) continue;
|
||||
for (var eventData in eventsData) {
|
||||
final eventId = eventData['id'] as String;
|
||||
if (excludeEventId != null && eventId == excludeEventId) continue;
|
||||
|
||||
try {
|
||||
final event = EventModel.fromMap(doc.data(), doc.id);
|
||||
final event = EventModel.fromMap(eventData, eventId);
|
||||
|
||||
// Ignorer les événements annulés
|
||||
if (event.status == EventStatus.canceled) {
|
||||
@@ -366,7 +357,7 @@ class EventAvailabilityService {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('[EventAvailabilityService] Error processing event ${doc.id}: $e');
|
||||
print('[EventAvailabilityService] Error processing event $eventId: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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