Cette mise à jour refactorise en profondeur le chargement des événements sur la page Calendrier pour améliorer drastiquement les performances et la réactivité de l'application, en particulier pour les utilisateurs avec un grand nombre d'événements. Le système de chargement initial de tous les événements est remplacé par un mécanisme de lazy loading qui ne récupère que les données du mois affiché.
**Changements majeurs :**
- **Lazy Loading Côté Client (`EventProvider`) :**
- Une nouvelle méthode `loadMonthEvents` a été introduite pour charger uniquement les événements d'un mois spécifique (`year`, `month`).
- Un cache par mois (`_eventsByMonth`) a été mis en place pour éviter les rechargements inutiles lors de la navigation entre des mois déjà consultés.
- Ajout d'une fonction `preloadAdjacentMonths` qui charge en arrière-plan et silencieusement les mois précédent et suivant, assurant une navigation fluide dans le calendrier.
- **Nouveau Endpoint Backend (`getEventsByMonth`) :**
- Création d'un nouvel endpoint Cloud Function `getEventsByMonth` optimisé pour ne requêter que les événements dans une plage de dates (début et fin du mois).
- La fonction récupère les utilisateurs associés de manière optimisée en parallélisant les requêtes Firestore (Promise.all).
- La limite du nombre d'IDs par requête 'in' a été augmentée de 10 à 30 pour réduire le nombre d'appels à la base de données.
- **Intégration au Calendrier (`CalendarPage`) :**
- La page charge désormais les événements pour le mois courant au démarrage via `_loadCurrentMonthEvents`.
- Lorsqu'un utilisateur change de mois (`onPageChanged`), la page déclenche le chargement des données pour le nouveau mois, avec un préchargement des mois adjacents pour anticiper la navigation.
- Le chargement initial de tous les événements (`_loadEventsAsync`) a été déprécié.
- **Correction de la Séquence de Démarrage (`main.dart`) :**
- L'appel à `_autoLogin` est maintenant enveloppé dans `WidgetsBinding.instance.addPostFrameCallback`. Cela garantit que la navigation ne se produit qu'après le premier rendu de l'interface, évitant ainsi des erreurs potentielles de build/navigation concurrentes et fiabilisant le chargement initial des données utilisateur.
711 lines
24 KiB
Dart
711 lines
24 KiB
Dart
import 'package:em2rp/services/api_service.dart';
|
|
import 'package:em2rp/utils/debug_log.dart';
|
|
|
|
/// Service générique pour les opérations de lecture de données via Cloud Functions
|
|
class DataService {
|
|
final ApiService _apiService;
|
|
|
|
DataService(this._apiService);
|
|
|
|
/// Récupère toutes les options
|
|
Future<List<Map<String, dynamic>>> getOptions() async {
|
|
try {
|
|
final result = await _apiService.call('getOptions', {});
|
|
final options = result['options'] as List<dynamic>?;
|
|
if (options == null) return [];
|
|
return options.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des options: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère tous les types d'événements
|
|
Future<List<Map<String, dynamic>>> getEventTypes() async {
|
|
try {
|
|
final result = await _apiService.call('getEventTypes', {});
|
|
final eventTypes = result['eventTypes'] as List<dynamic>?;
|
|
if (eventTypes == null) return [];
|
|
return eventTypes.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des types d\'événements: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère tous les rôles
|
|
Future<List<Map<String, dynamic>>> getRoles() async {
|
|
try {
|
|
final result = await _apiService.call('getRoles', {});
|
|
final roles = result['roles'] as List<dynamic>?;
|
|
if (roles == null) return [];
|
|
return roles.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des rôles: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour les équipements d'un événement
|
|
Future<void> updateEventEquipment({
|
|
required String eventId,
|
|
List<Map<String, dynamic>>? assignedEquipment,
|
|
String? preparationStatus,
|
|
String? loadingStatus,
|
|
String? unloadingStatus,
|
|
String? returnStatus,
|
|
}) async {
|
|
try {
|
|
final data = <String, dynamic>{'eventId': eventId};
|
|
|
|
if (assignedEquipment != null) data['assignedEquipment'] = assignedEquipment;
|
|
if (preparationStatus != null) data['preparationStatus'] = preparationStatus;
|
|
if (loadingStatus != null) data['loadingStatus'] = loadingStatus;
|
|
if (unloadingStatus != null) data['unloadingStatus'] = unloadingStatus;
|
|
if (returnStatus != null) data['returnStatus'] = returnStatus;
|
|
|
|
await _apiService.call('updateEventEquipment', data);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour des équipements de l\'événement: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour uniquement le statut d'un équipement
|
|
Future<void> updateEquipmentStatusOnly({
|
|
required String equipmentId,
|
|
String? status,
|
|
int? availableQuantity,
|
|
}) async {
|
|
try {
|
|
final data = <String, dynamic>{'equipmentId': equipmentId};
|
|
|
|
if (status != null) data['status'] = status;
|
|
if (availableQuantity != null) data['availableQuantity'] = availableQuantity;
|
|
|
|
await _apiService.call('updateEquipmentStatusOnly', data);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour du statut de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour un événement
|
|
Future<void> updateEvent(String eventId, Map<String, dynamic> data) async {
|
|
try {
|
|
// Correction : fusionner eventId et les champs de data à la racine
|
|
final requestData = {'eventId': eventId, ...data};
|
|
await _apiService.call('updateEvent', requestData);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour de l\'événement: $e');
|
|
}
|
|
}
|
|
|
|
/// Supprime un événement
|
|
Future<void> deleteEvent(String eventId) async {
|
|
try {
|
|
await _apiService.call('deleteEvent', {'eventId': eventId});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la suppression de l\'événement: $e');
|
|
}
|
|
}
|
|
|
|
/// Crée un équipement
|
|
Future<void> createEquipment(String equipmentId, Map<String, dynamic> data) async {
|
|
try {
|
|
// S'assurer que l'ID est dans les données
|
|
final equipmentData = Map<String, dynamic>.from(data);
|
|
equipmentData['id'] = equipmentId;
|
|
|
|
await _apiService.call('createEquipment', equipmentData);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la création de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour un équipement
|
|
Future<void> updateEquipment(String equipmentId, Map<String, dynamic> data) async {
|
|
try {
|
|
await _apiService.call('updateEquipment', {
|
|
'equipmentId': equipmentId,
|
|
'data': data,
|
|
});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Supprime un équipement
|
|
Future<void> deleteEquipment(String equipmentId) async {
|
|
try {
|
|
await _apiService.call('deleteEquipment', {'equipmentId': equipmentId});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la suppression de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère les événements utilisant un type d'événement donné
|
|
Future<List<Map<String, dynamic>>> getEventsByEventType(String eventTypeId) async {
|
|
try {
|
|
final result = await _apiService.call('getEventsByEventType', {'eventTypeId': eventTypeId});
|
|
final events = result['events'] as List<dynamic>?;
|
|
if (events == null) return [];
|
|
return events.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des événements: $e');
|
|
}
|
|
}
|
|
|
|
/// Crée un type d'événement
|
|
Future<String> createEventType({
|
|
required String name,
|
|
required double defaultPrice,
|
|
}) async {
|
|
try {
|
|
final result = await _apiService.call('createEventType', {
|
|
'name': name,
|
|
'defaultPrice': defaultPrice,
|
|
});
|
|
return result['id'] as String;
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la création du type d\'événement: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour un type d'événement
|
|
Future<void> updateEventType({
|
|
required String eventTypeId,
|
|
String? name,
|
|
double? defaultPrice,
|
|
}) async {
|
|
try {
|
|
final data = <String, dynamic>{'eventTypeId': eventTypeId};
|
|
if (name != null) data['name'] = name;
|
|
if (defaultPrice != null) data['defaultPrice'] = defaultPrice;
|
|
|
|
await _apiService.call('updateEventType', data);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour du type d\'événement: $e');
|
|
}
|
|
}
|
|
|
|
/// Supprime un type d'événement
|
|
Future<void> deleteEventType(String eventTypeId) async {
|
|
try {
|
|
await _apiService.call('deleteEventType', {'eventTypeId': eventTypeId});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la suppression du type d\'événement: $e');
|
|
}
|
|
}
|
|
|
|
/// Crée une option
|
|
Future<String> createOption(String code, Map<String, dynamic> data) async {
|
|
try {
|
|
final requestData = {
|
|
'id': code, // Ajouter l'ID en utilisant le code comme identifiant
|
|
'code': code,
|
|
...data
|
|
};
|
|
final result = await _apiService.call('createOption', requestData);
|
|
return result['id'] as String? ?? code;
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la création de l\'option: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour une option
|
|
Future<void> updateOption(String optionId, Map<String, dynamic> data) async {
|
|
try {
|
|
final requestData = {'optionId': optionId, ...data};
|
|
await _apiService.call('updateOption', requestData);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour de l\'option: $e');
|
|
}
|
|
}
|
|
|
|
/// Supprime une option
|
|
Future<void> deleteOption(String optionId) async {
|
|
try {
|
|
await _apiService.call('deleteOption', {'optionId': optionId});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la suppression de l\'option: $e');
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// LECTURE DES DONNÉES (avec permissions côté serveur)
|
|
// ============================================================================
|
|
|
|
/// Récupère tous les événements (filtrés selon permissions)
|
|
/// Retourne { events: List<Map>, users: Map<String, Map> }
|
|
Future<Map<String, dynamic>> getEvents({String? userId}) async {
|
|
try {
|
|
final data = <String, dynamic>{};
|
|
if (userId != null) data['userId'] = userId;
|
|
|
|
final result = await _apiService.call('getEvents', data);
|
|
|
|
// Extraire events et users
|
|
final events = result['events'] as List<dynamic>? ?? [];
|
|
final users = result['users'] as Map<String, dynamic>? ?? {};
|
|
|
|
return {
|
|
'events': events.map((e) => e as Map<String, dynamic>).toList(),
|
|
'users': users,
|
|
};
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des événements: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère les événements d'un mois spécifique (lazy loading optimisé)
|
|
Future<Map<String, dynamic>> getEventsByMonth({
|
|
required String userId,
|
|
required int year,
|
|
required int month,
|
|
}) async {
|
|
try {
|
|
print('[DataService] Calling getEventsByMonth for $year-$month');
|
|
final result = await _apiService.call('getEventsByMonth', {
|
|
'userId': userId,
|
|
'year': year,
|
|
'month': month,
|
|
});
|
|
|
|
// Extraire events et users
|
|
final events = result['events'] as List<dynamic>? ?? [];
|
|
final users = result['users'] as Map<String, dynamic>? ?? {};
|
|
|
|
print('[DataService] Events loaded for $year-$month: ${events.length} events');
|
|
|
|
return {
|
|
'events': events.map((e) => e as Map<String, dynamic>).toList(),
|
|
'users': users,
|
|
};
|
|
} catch (e) {
|
|
print('[DataService] Error getting events by month: $e');
|
|
throw Exception('Erreur lors de la récupération des événements du mois: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère un événement avec tous les détails (équipements complets + containers avec enfants)
|
|
Future<Map<String, dynamic>> getEventWithDetails(String eventId) async {
|
|
try {
|
|
print('[DataService] Getting event with details: $eventId');
|
|
final result = await _apiService.call('getEventWithDetails', {
|
|
'eventId': eventId,
|
|
});
|
|
|
|
final event = result['event'] as Map<String, dynamic>?;
|
|
final equipments = result['equipments'] as Map<String, dynamic>? ?? {};
|
|
final containers = result['containers'] as Map<String, dynamic>? ?? {};
|
|
|
|
if (event == null) {
|
|
throw Exception('Event not found');
|
|
}
|
|
|
|
print('[DataService] Event loaded with ${equipments.length} equipments and ${containers.length} containers');
|
|
|
|
return {
|
|
'event': event,
|
|
'equipments': equipments,
|
|
'containers': containers,
|
|
};
|
|
} catch (e) {
|
|
print('[DataService] Error getting event with details: $e');
|
|
throw Exception('Erreur lors de la récupération de l\'événement avec détails: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère tous les équipements (avec masquage des prix selon permissions)
|
|
Future<List<Map<String, dynamic>>> getEquipments() async {
|
|
try {
|
|
print('[DataService] Calling getEquipments API...');
|
|
final result = await _apiService.call('getEquipments', {});
|
|
print('[DataService] API call successful, parsing result...');
|
|
final equipments = result['equipments'] as List<dynamic>?;
|
|
if (equipments == null) {
|
|
print('[DataService] No equipments in result');
|
|
return [];
|
|
}
|
|
print('[DataService] Found ${equipments.length} equipments');
|
|
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
print('[DataService] Error getting equipments: $e');
|
|
throw Exception('Erreur lors de la récupération des équipements: $e');
|
|
}
|
|
}
|
|
|
|
/// 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 {
|
|
final result = await _apiService.call('getContainers', {});
|
|
final containers = result['containers'] as List<dynamic>?;
|
|
if (containers == null) return [];
|
|
return containers.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des conteneurs: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère plusieurs containers 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 containers: $e');
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// EQUIPMENTS & CONTAINERS - Pagination
|
|
// ============================================================================
|
|
|
|
/// Récupère les équipements avec pagination et filtrage
|
|
Future<Map<String, dynamic>> getEquipmentsPaginated({
|
|
int limit = 20,
|
|
String? startAfter,
|
|
String? category,
|
|
String? status,
|
|
String? searchQuery,
|
|
String sortBy = 'id',
|
|
String sortOrder = 'asc',
|
|
}) async {
|
|
try {
|
|
final params = <String, dynamic>{
|
|
'limit': limit,
|
|
'sortBy': sortBy,
|
|
'sortOrder': sortOrder,
|
|
};
|
|
|
|
if (startAfter != null) params['startAfter'] = startAfter;
|
|
if (category != null) params['category'] = category;
|
|
if (status != null) params['status'] = status;
|
|
if (searchQuery != null && searchQuery.isNotEmpty) {
|
|
params['searchQuery'] = searchQuery;
|
|
}
|
|
|
|
final result = await (_apiService as FirebaseFunctionsApiService).callPaginated(
|
|
'getEquipmentsPaginated',
|
|
params,
|
|
);
|
|
|
|
return {
|
|
'equipments': (result['equipments'] as List<dynamic>?)
|
|
?.map((e) => e as Map<String, dynamic>)
|
|
.toList() ?? [],
|
|
'hasMore': result['hasMore'] as bool? ?? false,
|
|
'lastVisible': result['lastVisible'] as String?,
|
|
'total': result['total'] as int? ?? 0,
|
|
};
|
|
} catch (e) {
|
|
DebugLog.error('[DataService] Error in getEquipmentsPaginated', e);
|
|
throw Exception('Erreur lors de la récupération paginée des équipements: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère les containers avec pagination et filtrage
|
|
Future<Map<String, dynamic>> getContainersPaginated({
|
|
int limit = 20,
|
|
String? startAfter,
|
|
String? type,
|
|
String? status,
|
|
String? searchQuery,
|
|
String? category,
|
|
String sortBy = 'id',
|
|
String sortOrder = 'asc',
|
|
}) async {
|
|
try {
|
|
final params = <String, dynamic>{
|
|
'limit': limit,
|
|
'sortBy': sortBy,
|
|
'sortOrder': sortOrder,
|
|
};
|
|
|
|
if (startAfter != null) params['startAfter'] = startAfter;
|
|
if (type != null) params['type'] = type;
|
|
if (status != null) params['status'] = status;
|
|
if (category != null) params['category'] = category;
|
|
if (searchQuery != null && searchQuery.isNotEmpty) {
|
|
params['searchQuery'] = searchQuery;
|
|
}
|
|
|
|
final result = await (_apiService as FirebaseFunctionsApiService).callPaginated(
|
|
'getContainersPaginated',
|
|
params,
|
|
);
|
|
|
|
return {
|
|
'containers': (result['containers'] as List<dynamic>?)
|
|
?.map((e) => e as Map<String, dynamic>)
|
|
.toList() ?? [],
|
|
'hasMore': result['hasMore'] as bool? ?? false,
|
|
'lastVisible': result['lastVisible'] as String?,
|
|
'total': result['total'] as int? ?? 0,
|
|
};
|
|
} catch (e) {
|
|
DebugLog.error('[DataService] Error in getContainersPaginated', e);
|
|
throw Exception('Erreur lors de la récupération paginée des containers: $e');
|
|
}
|
|
}
|
|
|
|
/// Recherche rapide (autocomplétion)
|
|
Future<List<Map<String, dynamic>>> quickSearch(
|
|
String query, {
|
|
int limit = 10,
|
|
bool includeEquipments = true,
|
|
bool includeContainers = true,
|
|
}) async {
|
|
try {
|
|
return await (_apiService as FirebaseFunctionsApiService).quickSearch(
|
|
query,
|
|
limit: limit,
|
|
includeEquipments: includeEquipments,
|
|
includeContainers: includeContainers,
|
|
);
|
|
} catch (e) {
|
|
DebugLog.error('[DataService] Error in quickSearch', e);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// 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');
|
|
}
|
|
}
|
|
|
|
/// Récupère tous les IDs d'équipements et conteneurs en conflit pour une période
|
|
/// Optimisé : une seule requête au lieu d'une par équipement
|
|
Future<Map<String, dynamic>> getConflictingEquipmentIds({
|
|
required DateTime startDate,
|
|
required DateTime endDate,
|
|
String? excludeEventId,
|
|
int installationTime = 0,
|
|
int disassemblyTime = 0,
|
|
}) async {
|
|
try {
|
|
final result = await _apiService.call('getConflictingEquipmentIds', {
|
|
'startDate': startDate.toIso8601String(),
|
|
'endDate': endDate.toIso8601String(),
|
|
if (excludeEventId != null) 'excludeEventId': excludeEventId,
|
|
'installationTime': installationTime,
|
|
'disassemblyTime': disassemblyTime,
|
|
});
|
|
return result;
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des équipements en conflit: $e');
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// MAINTENANCES
|
|
// ============================================================================
|
|
|
|
/// Récupère toutes les maintenances
|
|
Future<List<Map<String, dynamic>>> getMaintenances({String? equipmentId}) async {
|
|
try {
|
|
final data = <String, dynamic>{};
|
|
if (equipmentId != null) data['equipmentId'] = equipmentId;
|
|
|
|
final result = await _apiService.call('getMaintenances', data);
|
|
final maintenances = result['maintenances'] as List<dynamic>?;
|
|
if (maintenances == null) return [];
|
|
return maintenances.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des maintenances: $e');
|
|
}
|
|
}
|
|
|
|
/// 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');
|
|
}
|
|
}
|
|
|
|
/// Récupère les containers contenant un équipement
|
|
Future<List<Map<String, dynamic>>> getContainersByEquipment(String equipmentId) async {
|
|
try {
|
|
final result = await _apiService.call('getContainersByEquipment', {
|
|
'equipmentId': equipmentId,
|
|
});
|
|
final containers = result['containers'] as List<dynamic>?;
|
|
if (containers == null) return [];
|
|
return containers.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des containers: $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 {
|
|
await _apiService.call('updateUser', {
|
|
'userId': userId,
|
|
'data': data,
|
|
});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour de l\'utilisateur: $e');
|
|
}
|
|
}
|
|
|
|
/// Crée un utilisateur avec invitation par email
|
|
Future<Map<String, dynamic>> createUserWithInvite({
|
|
required String email,
|
|
required String firstName,
|
|
required String lastName,
|
|
String? phoneNumber,
|
|
required String roleId,
|
|
}) async {
|
|
try {
|
|
final result = await _apiService.call('createUserWithInvite', {
|
|
'email': email,
|
|
'firstName': firstName,
|
|
'lastName': lastName,
|
|
'phoneNumber': phoneNumber ?? '',
|
|
'roleId': roleId,
|
|
});
|
|
return result;
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la création de l\'utilisateur: $e');
|
|
}
|
|
}
|
|
}
|