feat: implement comprehensive Firebase Functions backend for equipment management and migrate core repository services
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/// Configuration de la version de l'application
|
||||
class AppVersion {
|
||||
static const String version = '1.2.1';
|
||||
static const String version = '1.2.3';
|
||||
|
||||
/// Retourne la version complète de l'application
|
||||
static String get fullVersion => 'v$version';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class Env {
|
||||
static const bool isDevelopment = true;
|
||||
static const bool isDevelopment = false;
|
||||
|
||||
// Configuration de l'auto-login en développement
|
||||
static const String devAdminEmail = 'paul.fournel@em2events.fr';
|
||||
static const String devAdminPassword = 'Pastis51!';
|
||||
static const String devAdminEmail = '';
|
||||
static const String devAdminPassword = '';
|
||||
|
||||
// URLs et endpoints
|
||||
static const String baseUrl = 'https://em2rp-951dc.firebaseapp.com';
|
||||
@@ -14,4 +14,3 @@ class Env {
|
||||
// Autres configurations
|
||||
static const int apiTimeout = 30000; // 30 secondes
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
|
||||
/// Repository pour gérer toutes les opérations sur les alertes.
|
||||
class AlertRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
AlertRepository(this._apiService);
|
||||
|
||||
/// 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
import 'package:em2rp/utils/debug_log.dart';
|
||||
|
||||
/// Repository pour gérer toutes les opérations sur les conteneurs.
|
||||
class ContainerRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
ContainerRepository(this._apiService);
|
||||
|
||||
/// 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(
|
||||
'[ContainerRepository] 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('[ContainerRepository] No containers in result');
|
||||
return [];
|
||||
}
|
||||
print('[ContainerRepository] Found ${containers.length} containers by IDs');
|
||||
return containers.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[ContainerRepository] Error getting containers by IDs: $e');
|
||||
throw Exception('Erreur lors de la récupération des containers: $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('[ContainerRepository] Error in getContainersPaginated', e);
|
||||
throw Exception(
|
||||
'Erreur lors de la récupération paginée des containers: $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');
|
||||
}
|
||||
}
|
||||
|
||||
/// Vérifie la disponibilité d'un container
|
||||
Future<Map<String, dynamic>> checkContainerAvailability({
|
||||
required String containerId,
|
||||
required DateTime startDate,
|
||||
required DateTime endDate,
|
||||
String? excludeEventId,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _apiService.call('checkContainerAvailability', {
|
||||
'containerId': containerId,
|
||||
'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é du container: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
import 'package:em2rp/utils/debug_log.dart';
|
||||
|
||||
/// Repository pour gérer toutes les opérations sur les équipements.
|
||||
class EquipmentRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
EquipmentRepository(this._apiService);
|
||||
|
||||
/// Récupère tous les équipements (avec masquage des prix selon permissions)
|
||||
Future<List<Map<String, dynamic>>> getEquipments() async {
|
||||
try {
|
||||
print('[EquipmentRepository] Calling getEquipments API...');
|
||||
final result = await _apiService.call('getEquipments', {});
|
||||
print('[EquipmentRepository] API call successful, parsing result...');
|
||||
final equipments = result['equipments'] as List<dynamic>?;
|
||||
if (equipments == null) {
|
||||
print('[EquipmentRepository] No equipments in result');
|
||||
return [];
|
||||
}
|
||||
print('[EquipmentRepository] Found ${equipments.length} equipments');
|
||||
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[EquipmentRepository] 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(
|
||||
'[EquipmentRepository] 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('[EquipmentRepository] No equipments in result');
|
||||
return [];
|
||||
}
|
||||
print('[EquipmentRepository] Found ${equipments.length} equipments by IDs');
|
||||
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[EquipmentRepository] Error getting equipments by IDs: $e');
|
||||
throw Exception('Erreur lors de la récupération des équipements: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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('[EquipmentRepository] Error in getEquipmentsPaginated', e);
|
||||
throw Exception(
|
||||
'Erreur lors de la récupération paginée des équipements: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Crée un équipement
|
||||
Future<void> createEquipment(
|
||||
String equipmentId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
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,
|
||||
{bool forceDelete = false}) async {
|
||||
try {
|
||||
await _apiService.call('deleteEquipment', {
|
||||
'equipmentId': equipmentId,
|
||||
'forceDelete': forceDelete,
|
||||
});
|
||||
} on ApiException {
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de l\'équipement: $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');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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('[EquipmentRepository] Error in quickSearch', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Recherche des équipements pour l'assistant IA avec fallback paginé.
|
||||
Future<List<Map<String, dynamic>>> searchEquipmentsForAssistant({
|
||||
required String query,
|
||||
int limit = 12,
|
||||
}) async {
|
||||
final normalizedQuery = query.trim();
|
||||
if (normalizedQuery.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
final quickResults = await quickSearch(
|
||||
normalizedQuery,
|
||||
limit: limit,
|
||||
includeEquipments: true,
|
||||
includeContainers: false,
|
||||
);
|
||||
|
||||
final equipmentResults = quickResults
|
||||
.where((item) =>
|
||||
(item['type']?.toString().toLowerCase() ?? '') == 'equipment')
|
||||
.map(_normalizeAssistantEquipment)
|
||||
.toList();
|
||||
|
||||
if (equipmentResults.isNotEmpty) {
|
||||
return equipmentResults;
|
||||
}
|
||||
|
||||
final paginated = await getEquipmentsPaginated(
|
||||
limit: limit,
|
||||
searchQuery: normalizedQuery,
|
||||
sortBy: 'id',
|
||||
sortOrder: 'asc',
|
||||
);
|
||||
|
||||
final equipments =
|
||||
paginated['equipments'] as List<Map<String, dynamic>>? ?? [];
|
||||
return equipments.map(_normalizeAssistantEquipment).toList();
|
||||
} catch (e) {
|
||||
DebugLog.error('[EquipmentRepository] Error in searchEquipmentsForAssistant', e);
|
||||
throw Exception('Erreur lors de la recherche de matériel: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Vérifie la disponibilité d'un équipement dans un format normalisé pour l'IA.
|
||||
Future<Map<String, dynamic>> checkEquipmentAvailabilityForAssistant({
|
||||
required String equipmentId,
|
||||
required DateTime startDate,
|
||||
required DateTime endDate,
|
||||
String? excludeEventId,
|
||||
}) async {
|
||||
try {
|
||||
final result = await checkEquipmentAvailability(
|
||||
equipmentId: equipmentId,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
excludeEventId: excludeEventId,
|
||||
);
|
||||
|
||||
final available = result['available'] as bool? ?? true;
|
||||
final conflicts = (result['conflicts'] as List<dynamic>? ?? const [])
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map((conflict) {
|
||||
final eventData =
|
||||
conflict['eventData'] as Map<String, dynamic>? ?? const {};
|
||||
final eventName =
|
||||
(eventData['Name'] ?? conflict['eventName'] ?? '').toString();
|
||||
return {
|
||||
'eventId': conflict['eventId']?.toString() ?? '',
|
||||
'eventName': eventName,
|
||||
'overlapDays': conflict['overlapDays'] as int? ?? 0,
|
||||
};
|
||||
}).toList();
|
||||
|
||||
return {
|
||||
'equipmentId': equipmentId,
|
||||
'available': available,
|
||||
'conflictCount': conflicts.length,
|
||||
'conflicts': conflicts,
|
||||
};
|
||||
} catch (e) {
|
||||
DebugLog.error(
|
||||
'[EquipmentRepository] Error in checkEquipmentAvailabilityForAssistant', e);
|
||||
throw Exception('Erreur lors de la vérification de disponibilité: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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');
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _normalizeAssistantEquipment(Map<String, dynamic> item) {
|
||||
return {
|
||||
'id': (item['id'] ?? '').toString(),
|
||||
'name': (item['name'] ?? item['id'] ?? '').toString(),
|
||||
'category': (item['category'] ?? '').toString(),
|
||||
'status': (item['status'] ?? '').toString(),
|
||||
'brand': item['brand']?.toString(),
|
||||
'model': item['model']?.toString(),
|
||||
'availableQuantity': item['availableQuantity'],
|
||||
'totalQuantity': item['totalQuantity'],
|
||||
};
|
||||
}
|
||||
|
||||
/// 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
|
||||
/// Repository pour gérer toutes les opérations sur les événements.
|
||||
class EventRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
EventRepository(this._apiService);
|
||||
|
||||
/// 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 un événement
|
||||
Future<void> updateEvent(String eventId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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('[EventRepository] 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(
|
||||
'[EventRepository] Events loaded for $year-$month: ${events.length} events');
|
||||
|
||||
return {
|
||||
'events': events.map((e) => e as Map<String, dynamic>).toList(),
|
||||
'users': users,
|
||||
};
|
||||
} catch (e) {
|
||||
print('[EventRepository] Error getting events by month: $e');
|
||||
throw Exception(
|
||||
'Erreur lors de la récupération des événements du mois: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Recherche des événements accessibles à l'utilisateur.
|
||||
Future<List<Map<String, dynamic>>> searchEvents({
|
||||
required String userId,
|
||||
required String query,
|
||||
int limit = 20,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _apiService.call('searchEvents', {
|
||||
'userId': userId,
|
||||
'query': query,
|
||||
'limit': limit,
|
||||
});
|
||||
|
||||
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 recherche d\'événements: $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('[EventRepository] 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(
|
||||
'[EventRepository] Event loaded with ${equipments.length} equipments and ${containers.length} containers');
|
||||
|
||||
return {
|
||||
'event': event,
|
||||
'equipments': equipments,
|
||||
'containers': containers,
|
||||
};
|
||||
} catch (e) {
|
||||
print('[EventRepository] Error getting event with details: $e');
|
||||
throw Exception(
|
||||
'Erreur lors de la récupération de l\'événement avec détails: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
|
||||
/// Repository pour gérer toutes les opérations sur les options et types d'événements.
|
||||
class OptionRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
OptionRepository(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');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
'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': 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import 'package:em2rp/services/api_service.dart';
|
||||
|
||||
/// Repository pour gérer toutes les opérations sur les utilisateurs et les rôles.
|
||||
class UserRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
UserRepository(this._apiService);
|
||||
|
||||
/// Récupère l'utilisateur actuellement authentifié avec son rôle
|
||||
Future<Map<String, dynamic>> getCurrentUser() async {
|
||||
try {
|
||||
print('[UserRepository] Calling getCurrentUser API...');
|
||||
final result = await _apiService.call('getCurrentUser', {});
|
||||
print('[UserRepository] Current user loaded successfully');
|
||||
return result['user'] as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
print('[UserRepository] Error getting current user: $e');
|
||||
throw Exception(
|
||||
'Erreur lors de la récupération de l\'utilisateur actuel: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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');
|
||||
}
|
||||
}
|
||||
|
||||
/// 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -171,20 +171,37 @@ class EventAvailabilityService {
|
||||
for (var conflictData in containerConflicts) {
|
||||
final conflict = conflictData as Map<String, dynamic>;
|
||||
final eventId = conflict['eventId'] as String;
|
||||
final eventDoc = await _dataService.getEvents();
|
||||
final eventData = (eventDoc['events'] as List<dynamic>).firstWhere((e) => e['id'] == eventId, orElse: () => null);
|
||||
if (eventData != null) {
|
||||
final event = EventModel.fromMap(eventData as Map<String, dynamic>, eventId);
|
||||
conflicts.add(AvailabilityConflict(
|
||||
equipmentId: container.id,
|
||||
equipmentName: container.name,
|
||||
conflictingEvent: event,
|
||||
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
||||
type: ConflictType.containerFullyUsed,
|
||||
containerId: container.id,
|
||||
containerName: container.name,
|
||||
));
|
||||
}
|
||||
final eventName = conflict['eventName'] as String? ?? '';
|
||||
final startDateStr = conflict['startDate'] as String?;
|
||||
final endDateStr = conflict['endDate'] as String?;
|
||||
|
||||
final event = EventModel(
|
||||
id: eventId,
|
||||
name: eventName,
|
||||
description: '',
|
||||
startDateTime: startDateStr != null ? DateTime.tryParse(startDateStr) ?? DateTime.now() : DateTime.now(),
|
||||
endDateTime: endDateStr != null ? DateTime.tryParse(endDateStr) ?? DateTime.now() : DateTime.now(),
|
||||
basePrice: 0.0,
|
||||
installationTime: 0,
|
||||
disassemblyTime: 0,
|
||||
eventTypeId: '',
|
||||
customerId: '',
|
||||
address: '',
|
||||
latitude: 0.0,
|
||||
longitude: 0.0,
|
||||
workforce: const [],
|
||||
documents: const [],
|
||||
);
|
||||
|
||||
conflicts.add(AvailabilityConflict(
|
||||
equipmentId: container.id,
|
||||
equipmentName: container.name,
|
||||
conflictingEvent: event,
|
||||
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
||||
type: ConflictType.containerFullyUsed,
|
||||
containerId: container.id,
|
||||
containerName: container.name,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user