Initialisation du projet geosector complet (web + flutter)
This commit is contained in:
208
flutt/lib/core/repositories/membre_repository.dart
Normal file
208
flutt/lib/core/repositories/membre_repository.dart
Normal file
@@ -0,0 +1,208 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/data/models/membre_model.dart';
|
||||
|
||||
class MembreRepository extends ChangeNotifier {
|
||||
// Utilisation de getters lazy pour n'accéder à la boîte que lorsque nécessaire
|
||||
Box<MembreModel> get _membreBox =>
|
||||
Hive.box<MembreModel>(AppKeys.membresBoxName);
|
||||
|
||||
final ApiService _apiService;
|
||||
bool _isLoading = false;
|
||||
|
||||
MembreRepository(this._apiService);
|
||||
|
||||
// Getters
|
||||
bool get isLoading => _isLoading;
|
||||
List<MembreModel> get membres => getAllMembres();
|
||||
|
||||
// Méthode pour vérifier si une boîte est ouverte et l'ouvrir si nécessaire
|
||||
Future<void> _ensureBoxIsOpen() async {
|
||||
try {
|
||||
if (!Hive.isBoxOpen(AppKeys.membresBoxName)) {
|
||||
debugPrint('Ouverture de la boîte ${AppKeys.membresBoxName}...');
|
||||
await Hive.openBox<MembreModel>(AppKeys.membresBoxName);
|
||||
debugPrint('Boîte ${AppKeys.membresBoxName} ouverte avec succès');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de l\'ouverture de la boîte ${AppKeys.membresBoxName}: $e');
|
||||
throw Exception(
|
||||
'Impossible d\'ouvrir la boîte ${AppKeys.membresBoxName}: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer tous les membres
|
||||
List<MembreModel> getAllMembres() {
|
||||
try {
|
||||
return _membreBox.values.toList();
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération des membres: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer un membre par son ID
|
||||
MembreModel? getMembreById(int id) {
|
||||
try {
|
||||
return _membreBox.get(id);
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération du membre: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Créer ou mettre à jour un membre
|
||||
Future<MembreModel> saveMembre(MembreModel membre) async {
|
||||
await _ensureBoxIsOpen();
|
||||
await _membreBox.put(membre.id, membre);
|
||||
notifyListeners();
|
||||
return membre;
|
||||
}
|
||||
|
||||
// Supprimer un membre
|
||||
Future<void> deleteMembre(int id) async {
|
||||
await _ensureBoxIsOpen();
|
||||
await _membreBox.delete(id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Récupérer les membres depuis l'API (uniquement pour l'interface admin)
|
||||
Future<List<MembreModel>> fetchMembresFromApi() async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
if (!hasConnection) {
|
||||
debugPrint(
|
||||
'Pas de connexion Internet, utilisation des données locales');
|
||||
return getAllMembres();
|
||||
}
|
||||
|
||||
// Endpoint à adapter selon votre API
|
||||
final response = await _apiService.get('/membres');
|
||||
final List<dynamic> membresData = response.data['membres'];
|
||||
|
||||
// Vider la boîte avant d'ajouter les nouveaux membres
|
||||
await _ensureBoxIsOpen();
|
||||
await _membreBox.clear();
|
||||
|
||||
final List<MembreModel> membres = [];
|
||||
for (var membreData in membresData) {
|
||||
try {
|
||||
final membre = MembreModel.fromJson(membreData);
|
||||
await _membreBox.put(membre.id, membre);
|
||||
membres.add(membre);
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du traitement d\'un membre: $e');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
return membres;
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la récupération des membres depuis l\'API: $e');
|
||||
return getAllMembres();
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Créer un membre via l'API
|
||||
Future<MembreModel?> createMembreViaApi(MembreModel membre) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
if (!hasConnection) {
|
||||
debugPrint('Pas de connexion Internet, impossible de créer le membre');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Endpoint à adapter selon votre API
|
||||
final response =
|
||||
await _apiService.post('/membres', data: membre.toJson());
|
||||
final membreData = response.data['membre'];
|
||||
|
||||
final newMembre = MembreModel.fromJson(membreData);
|
||||
await saveMembre(newMembre);
|
||||
|
||||
return newMembre;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la création du membre via l\'API: $e');
|
||||
return null;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour un membre via l'API
|
||||
Future<MembreModel?> updateMembreViaApi(MembreModel membre) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
if (!hasConnection) {
|
||||
debugPrint(
|
||||
'Pas de connexion Internet, impossible de mettre à jour le membre');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Endpoint à adapter selon votre API
|
||||
final response =
|
||||
await _apiService.put('/membres/${membre.id}', data: membre.toJson());
|
||||
final membreData = response.data['membre'];
|
||||
|
||||
final updatedMembre = MembreModel.fromJson(membreData);
|
||||
await saveMembre(updatedMembre);
|
||||
|
||||
return updatedMembre;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la mise à jour du membre via l\'API: $e');
|
||||
return null;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer un membre via l'API
|
||||
Future<bool> deleteMembreViaApi(int id) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
if (!hasConnection) {
|
||||
debugPrint(
|
||||
'Pas de connexion Internet, impossible de supprimer le membre');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Endpoint à adapter selon votre API
|
||||
await _apiService.delete('/membres/$id');
|
||||
|
||||
// Supprimer localement
|
||||
await deleteMembre(id);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la suppression du membre via l\'API: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
215
flutt/lib/core/repositories/operation_repository.dart
Normal file
215
flutt/lib/core/repositories/operation_repository.dart
Normal file
@@ -0,0 +1,215 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:geosector_app/core/data/models/operation_model.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
|
||||
class OperationRepository extends ChangeNotifier {
|
||||
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
||||
// et vérifier qu'elle est ouverte avant accès
|
||||
Box<OperationModel> get _operationBox {
|
||||
_ensureBoxIsOpen();
|
||||
return Hive.box<OperationModel>(AppKeys.operationsBoxName);
|
||||
}
|
||||
|
||||
// Méthode pour vérifier si la boîte est ouverte et l'ouvrir si nécessaire
|
||||
Future<void> _ensureBoxIsOpen() async {
|
||||
final boxName = AppKeys.operationsBoxName;
|
||||
if (!Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Ouverture de la boîte $boxName dans OperationRepository...');
|
||||
await Hive.openBox<OperationModel>(boxName);
|
||||
}
|
||||
}
|
||||
final ApiService _apiService;
|
||||
|
||||
bool _isLoading = false;
|
||||
|
||||
OperationRepository(this._apiService);
|
||||
|
||||
// Getters
|
||||
bool get isLoading => _isLoading;
|
||||
List<OperationModel> get operations => getAllOperations();
|
||||
|
||||
// Récupérer toutes les opérations
|
||||
List<OperationModel> getAllOperations() {
|
||||
return _operationBox.values.toList();
|
||||
}
|
||||
|
||||
// Récupérer une opération par son ID
|
||||
OperationModel? getOperationById(int id) {
|
||||
return _operationBox.get(id);
|
||||
}
|
||||
|
||||
// Sauvegarder une opération
|
||||
Future<void> saveOperation(OperationModel operation) async {
|
||||
await _operationBox.put(operation.id, operation);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Supprimer une opération
|
||||
Future<void> deleteOperation(int id) async {
|
||||
await _operationBox.delete(id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Créer ou mettre à jour des opérations à partir des données de l'API
|
||||
Future<void> processOperationsFromApi(List<dynamic> operationsData) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
for (var operationData in operationsData) {
|
||||
final operationJson = operationData as Map<String, dynamic>;
|
||||
final operationId = operationJson['id'] is String
|
||||
? int.parse(operationJson['id'])
|
||||
: operationJson['id'] as int;
|
||||
|
||||
// Vérifier si l'opération existe déjà
|
||||
OperationModel? existingOperation = getOperationById(operationId);
|
||||
|
||||
if (existingOperation == null) {
|
||||
// Créer une nouvelle opération
|
||||
final newOperation = OperationModel.fromJson(operationJson);
|
||||
await saveOperation(newOperation);
|
||||
} else {
|
||||
// Mettre à jour l'opération existante
|
||||
final updatedOperation = existingOperation.copyWith(
|
||||
name: operationJson['name'],
|
||||
dateDebut: DateTime.parse(operationJson['date_deb']),
|
||||
dateFin: DateTime.parse(operationJson['date_fin']),
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isSynced: true,
|
||||
);
|
||||
await saveOperation(updatedOperation);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du traitement des opérations: $e');
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Créer une opération
|
||||
Future<bool> createOperation(String name, DateTime dateDebut, DateTime dateFin) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Préparer les données pour l'API
|
||||
final Map<String, dynamic> data = {
|
||||
'name': name,
|
||||
'date_deb': dateDebut.toIso8601String().split('T')[0], // Format YYYY-MM-DD
|
||||
'date_fin': dateFin.toIso8601String().split('T')[0], // Format YYYY-MM-DD
|
||||
};
|
||||
|
||||
// Appeler l'API pour créer l'opération
|
||||
final response = await _apiService.post('/operations', data: data);
|
||||
|
||||
if (response.statusCode == 201 || response.statusCode == 200) {
|
||||
// Récupérer l'ID de la nouvelle opération
|
||||
final operationId = response.data['id'] is String
|
||||
? int.parse(response.data['id'])
|
||||
: response.data['id'] as int;
|
||||
|
||||
// Créer l'opération localement
|
||||
final newOperation = OperationModel(
|
||||
id: operationId,
|
||||
name: name,
|
||||
dateDebut: dateDebut,
|
||||
dateFin: dateFin,
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isActive: true,
|
||||
isSynced: true,
|
||||
);
|
||||
|
||||
await saveOperation(newOperation);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la création de l\'opération: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour une opération
|
||||
Future<bool> updateOperation(int id, {String? name, DateTime? dateDebut, DateTime? dateFin, bool? isActive}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Récupérer l'opération existante
|
||||
final existingOperation = getOperationById(id);
|
||||
if (existingOperation == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Préparer les données pour l'API
|
||||
final Map<String, dynamic> data = {
|
||||
'id': id,
|
||||
'name': name ?? existingOperation.name,
|
||||
'date_deb': (dateDebut ?? existingOperation.dateDebut).toIso8601String().split('T')[0],
|
||||
'date_fin': (dateFin ?? existingOperation.dateFin).toIso8601String().split('T')[0],
|
||||
'is_active': isActive ?? existingOperation.isActive,
|
||||
};
|
||||
|
||||
// Appeler l'API pour mettre à jour l'opération
|
||||
final response = await _apiService.put('/operations/$id', data: data);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Mettre à jour l'opération localement
|
||||
final updatedOperation = existingOperation.copyWith(
|
||||
name: name,
|
||||
dateDebut: dateDebut,
|
||||
dateFin: dateFin,
|
||||
isActive: isActive,
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isSynced: true,
|
||||
);
|
||||
|
||||
await saveOperation(updatedOperation);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la mise à jour de l\'opération: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer une opération via l'API
|
||||
Future<bool> deleteOperationViaApi(int id) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Appeler l'API pour supprimer l'opération
|
||||
final response = await _apiService.delete('/operations/$id');
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 204) {
|
||||
// Supprimer l'opération localement
|
||||
await deleteOperation(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la suppression de l\'opération: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
381
flutt/lib/core/repositories/passage_repository.dart
Normal file
381
flutt/lib/core/repositories/passage_repository.dart
Normal file
@@ -0,0 +1,381 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:geosector_app/core/data/models/passage_model.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
|
||||
class PassageRepository extends ChangeNotifier {
|
||||
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
||||
// et vérifier qu'elle est ouverte avant accès
|
||||
Box<PassageModel> get _passageBox {
|
||||
_ensureBoxIsOpen();
|
||||
return Hive.box<PassageModel>(AppKeys.passagesBoxName);
|
||||
}
|
||||
|
||||
// Méthode pour vérifier si la boîte est ouverte et l'ouvrir si nécessaire
|
||||
Future<void> _ensureBoxIsOpen() async {
|
||||
final boxName = AppKeys.passagesBoxName;
|
||||
if (!Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Ouverture de la boîte $boxName dans PassageRepository...');
|
||||
await Hive.openBox<PassageModel>(boxName);
|
||||
}
|
||||
}
|
||||
final ApiService _apiService;
|
||||
|
||||
bool _isLoading = false;
|
||||
|
||||
PassageRepository(this._apiService);
|
||||
|
||||
// Getters
|
||||
bool get isLoading => _isLoading;
|
||||
List<PassageModel> get passages => getAllPassages();
|
||||
|
||||
// Récupérer tous les passages
|
||||
List<PassageModel> getAllPassages() {
|
||||
return _passageBox.values.toList();
|
||||
}
|
||||
|
||||
// Récupérer un passage par son ID
|
||||
PassageModel? getPassageById(int id) {
|
||||
return _passageBox.get(id);
|
||||
}
|
||||
|
||||
// Récupérer les passages par secteur
|
||||
List<PassageModel> getPassagesBySector(int sectorId) {
|
||||
return _passageBox.values
|
||||
.where((passage) => passage.fkSector == sectorId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Récupérer les passages par opération
|
||||
List<PassageModel> getPassagesByOperation(int operationId) {
|
||||
return _passageBox.values
|
||||
.where((passage) => passage.fkOperation == operationId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Récupérer les passages par type
|
||||
List<PassageModel> getPassagesByType(int typeId) {
|
||||
return _passageBox.values
|
||||
.where((passage) => passage.fkType == typeId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Récupérer les passages par type de règlement
|
||||
List<PassageModel> getPassagesByPaymentType(int paymentTypeId) {
|
||||
return _passageBox.values
|
||||
.where((passage) => passage.fkTypeReglement == paymentTypeId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Sauvegarder un passage
|
||||
Future<void> savePassage(PassageModel passage) async {
|
||||
await _passageBox.put(passage.id, passage);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Supprimer un passage
|
||||
Future<void> deletePassage(int id) async {
|
||||
await _passageBox.delete(id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Traiter les passages reçus de l'API
|
||||
Future<void> processPassagesFromApi(List<dynamic> passagesData) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
for (var passageData in passagesData) {
|
||||
final passageJson = passageData as Map<String, dynamic>;
|
||||
final passageId = passageJson['id'] is String
|
||||
? int.parse(passageJson['id'])
|
||||
: passageJson['id'] as int;
|
||||
|
||||
// Vérifier si le passage existe déjà
|
||||
PassageModel? existingPassage = getPassageById(passageId);
|
||||
|
||||
if (existingPassage == null) {
|
||||
// Créer un nouveau passage
|
||||
final newPassage = PassageModel.fromJson(passageJson);
|
||||
await savePassage(newPassage);
|
||||
} else {
|
||||
// Mettre à jour le passage existant avec les nouvelles données
|
||||
final updatedPassage = PassageModel.fromJson(passageJson).copyWith(
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isActive: existingPassage.isActive,
|
||||
isSynced: true,
|
||||
);
|
||||
await savePassage(updatedPassage);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du traitement des passages: $e');
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Créer un nouveau passage
|
||||
Future<bool> createPassage({
|
||||
required int fkOperation,
|
||||
required int fkSector,
|
||||
required int fkUser,
|
||||
required int fkType,
|
||||
required String fkAdresse,
|
||||
required DateTime passedAt,
|
||||
required String numero,
|
||||
required String rue,
|
||||
String rueBis = '',
|
||||
required String ville,
|
||||
String residence = '',
|
||||
required int fkHabitat,
|
||||
String appt = '',
|
||||
String niveau = '',
|
||||
required String gpsLat,
|
||||
required String gpsLng,
|
||||
String nomRecu = '',
|
||||
String remarque = '',
|
||||
required String montant,
|
||||
required int fkTypeReglement,
|
||||
String name = '',
|
||||
String email = '',
|
||||
String phone = '',
|
||||
}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Préparer les données pour l'API
|
||||
final Map<String, dynamic> data = {
|
||||
'fk_operation': fkOperation,
|
||||
'fk_sector': fkSector,
|
||||
'fk_user': fkUser,
|
||||
'fk_type': fkType,
|
||||
'fk_adresse': fkAdresse,
|
||||
'passed_at': passedAt.toIso8601String(),
|
||||
'numero': numero,
|
||||
'rue': rue,
|
||||
'rue_bis': rueBis,
|
||||
'ville': ville,
|
||||
'residence': residence,
|
||||
'fk_habitat': fkHabitat,
|
||||
'appt': appt,
|
||||
'niveau': niveau,
|
||||
'gps_lat': gpsLat,
|
||||
'gps_lng': gpsLng,
|
||||
'nom_recu': nomRecu,
|
||||
'remarque': remarque,
|
||||
'montant': montant,
|
||||
'fk_type_reglement': fkTypeReglement,
|
||||
'name': name,
|
||||
'email': email,
|
||||
'phone': phone,
|
||||
};
|
||||
|
||||
// Appeler l'API pour créer le passage
|
||||
final response = await _apiService.post('/passages', data: data);
|
||||
|
||||
if (response.statusCode == 201 || response.statusCode == 200) {
|
||||
// Récupérer l'ID du nouveau passage
|
||||
final passageId = response.data['id'] is String
|
||||
? int.parse(response.data['id'])
|
||||
: response.data['id'] as int;
|
||||
|
||||
// Créer le modèle local
|
||||
final newPassage = PassageModel(
|
||||
id: passageId,
|
||||
fkOperation: fkOperation,
|
||||
fkSector: fkSector,
|
||||
fkUser: fkUser,
|
||||
fkType: fkType,
|
||||
fkAdresse: fkAdresse,
|
||||
passedAt: passedAt,
|
||||
numero: numero,
|
||||
rue: rue,
|
||||
rueBis: rueBis,
|
||||
ville: ville,
|
||||
residence: residence,
|
||||
fkHabitat: fkHabitat,
|
||||
appt: appt,
|
||||
niveau: niveau,
|
||||
gpsLat: gpsLat,
|
||||
gpsLng: gpsLng,
|
||||
nomRecu: nomRecu,
|
||||
remarque: remarque,
|
||||
montant: montant,
|
||||
fkTypeReglement: fkTypeReglement,
|
||||
nbPassages: 1, // Par défaut pour un nouveau passage
|
||||
name: name,
|
||||
email: email,
|
||||
phone: phone,
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isActive: true,
|
||||
isSynced: true,
|
||||
);
|
||||
|
||||
await savePassage(newPassage);
|
||||
return true;
|
||||
} else {
|
||||
debugPrint('Erreur lors de la création du passage: ${response.statusMessage}');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la création du passage: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour un passage existant
|
||||
Future<bool> updatePassage(PassageModel passage) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Préparer les données pour l'API
|
||||
final Map<String, dynamic> data = passage.toJson();
|
||||
|
||||
// Appeler l'API pour mettre à jour le passage
|
||||
final response = await _apiService.put('/passages/${passage.id}', data: data);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Mettre à jour le modèle local
|
||||
final updatedPassage = passage.copyWith(
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isSynced: true,
|
||||
);
|
||||
|
||||
await savePassage(updatedPassage);
|
||||
return true;
|
||||
} else {
|
||||
debugPrint('Erreur lors de la mise à jour du passage: ${response.statusMessage}');
|
||||
|
||||
// Marquer comme non synchronisé mais sauvegarder localement
|
||||
final updatedPassage = passage.copyWith(
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isSynced: false,
|
||||
);
|
||||
|
||||
await savePassage(updatedPassage);
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la mise à jour du passage: $e');
|
||||
|
||||
// Marquer comme non synchronisé mais sauvegarder localement
|
||||
final updatedPassage = passage.copyWith(
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isSynced: false,
|
||||
);
|
||||
|
||||
await savePassage(updatedPassage);
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Synchroniser tous les passages non synchronisés
|
||||
Future<void> syncUnsyncedPassages() async {
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
|
||||
if (!hasConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
final unsyncedPassages = _passageBox.values.where((passage) => !passage.isSynced).toList();
|
||||
|
||||
if (unsyncedPassages.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
for (final passage in unsyncedPassages) {
|
||||
try {
|
||||
if (passage.id < 0) {
|
||||
// Nouveau passage créé localement, à envoyer à l'API
|
||||
await createPassage(
|
||||
fkOperation: passage.fkOperation,
|
||||
fkSector: passage.fkSector,
|
||||
fkUser: passage.fkUser,
|
||||
fkType: passage.fkType,
|
||||
fkAdresse: passage.fkAdresse,
|
||||
passedAt: passage.passedAt,
|
||||
numero: passage.numero,
|
||||
rue: passage.rue,
|
||||
rueBis: passage.rueBis,
|
||||
ville: passage.ville,
|
||||
residence: passage.residence,
|
||||
fkHabitat: passage.fkHabitat,
|
||||
appt: passage.appt,
|
||||
niveau: passage.niveau,
|
||||
gpsLat: passage.gpsLat,
|
||||
gpsLng: passage.gpsLng,
|
||||
nomRecu: passage.nomRecu,
|
||||
remarque: passage.remarque,
|
||||
montant: passage.montant,
|
||||
fkTypeReglement: passage.fkTypeReglement,
|
||||
name: passage.name,
|
||||
email: passage.email,
|
||||
phone: passage.phone,
|
||||
);
|
||||
|
||||
// Supprimer l'ancien passage avec ID temporaire
|
||||
await deletePassage(passage.id);
|
||||
} else {
|
||||
// Passage existant à mettre à jour
|
||||
await updatePassage(passage);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la synchronisation du passage ${passage.id}: $e');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la synchronisation des passages: $e');
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer les passages depuis l'API
|
||||
Future<void> fetchPassages() async {
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
|
||||
if (!hasConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
final response = await _apiService.get('/passages');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final List<dynamic> passagesData = response.data;
|
||||
await processPassagesFromApi(passagesData);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération des passages: $e');
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Vider tous les passages
|
||||
Future<void> clearAllPassages() async {
|
||||
await _passageBox.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
149
flutt/lib/core/repositories/sector_repository.dart
Normal file
149
flutt/lib/core/repositories/sector_repository.dart
Normal file
@@ -0,0 +1,149 @@
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:geosector_app/core/data/models/sector_model.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
|
||||
class SectorRepository {
|
||||
final ApiService _apiService;
|
||||
|
||||
SectorRepository(this._apiService);
|
||||
|
||||
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
||||
// et vérifier qu'elle est ouverte avant accès
|
||||
Box<SectorModel> get _sectorsBox {
|
||||
_ensureBoxIsOpen();
|
||||
return Hive.box<SectorModel>(AppKeys.sectorsBoxName);
|
||||
}
|
||||
|
||||
// Méthode pour vérifier si la boîte est ouverte et l'ouvrir si nécessaire
|
||||
Future<void> _ensureBoxIsOpen() async {
|
||||
final boxName = AppKeys.sectorsBoxName;
|
||||
if (!Hive.isBoxOpen(boxName)) {
|
||||
print('Ouverture de la boîte $boxName dans SectorRepository...');
|
||||
await Hive.openBox<SectorModel>(boxName);
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer tous les secteurs depuis la base de données locale
|
||||
List<SectorModel> getAllSectors() {
|
||||
return _sectorsBox.values.toList();
|
||||
}
|
||||
|
||||
// Récupérer un secteur par son ID
|
||||
SectorModel? getSectorById(int id) {
|
||||
try {
|
||||
return _sectorsBox.values.firstWhere(
|
||||
(sector) => sector.id == id,
|
||||
);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Sauvegarder les secteurs dans la base de données locale
|
||||
Future<void> saveSectors(List<SectorModel> sectors) async {
|
||||
// Vider la box avant d'ajouter les nouveaux secteurs
|
||||
await _sectorsBox.clear();
|
||||
|
||||
// Ajouter les nouveaux secteurs
|
||||
for (final sector in sectors) {
|
||||
await _sectorsBox.put(sector.id, sector);
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter ou mettre à jour un secteur
|
||||
Future<void> saveSector(SectorModel sector) async {
|
||||
await _sectorsBox.put(sector.id, sector);
|
||||
}
|
||||
|
||||
// Supprimer un secteur
|
||||
Future<void> deleteSector(int id) async {
|
||||
await _sectorsBox.delete(id);
|
||||
}
|
||||
|
||||
// Récupérer les secteurs depuis l'API
|
||||
Future<List<SectorModel>> fetchSectorsFromApi() async {
|
||||
try {
|
||||
final response = await _apiService.get(AppKeys.sectorsEndpoint);
|
||||
final Map<String, dynamic> responseData = response as Map<String, dynamic>;
|
||||
|
||||
if (responseData['status'] == 'success' && responseData['sectors'] != null) {
|
||||
final List<dynamic> sectorsJson = responseData['sectors'];
|
||||
final List<SectorModel> sectors = sectorsJson
|
||||
.map((json) => SectorModel.fromJson(json))
|
||||
.toList();
|
||||
|
||||
// Sauvegarder les secteurs localement
|
||||
await saveSectors(sectors);
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
return [];
|
||||
} catch (e) {
|
||||
// En cas d'erreur, retourner les secteurs locaux
|
||||
return getAllSectors();
|
||||
}
|
||||
}
|
||||
|
||||
// Créer un nouveau secteur via l'API
|
||||
Future<SectorModel?> createSector(SectorModel sector) async {
|
||||
try {
|
||||
final response = await _apiService.post(
|
||||
AppKeys.sectorsEndpoint,
|
||||
data: sector.toJson(),
|
||||
);
|
||||
final Map<String, dynamic> responseData = response as Map<String, dynamic>;
|
||||
|
||||
if (responseData['status'] == 'success' && responseData['sector'] != null) {
|
||||
final SectorModel newSector = SectorModel.fromJson(responseData['sector']);
|
||||
await saveSector(newSector);
|
||||
return newSector;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour un secteur via l'API
|
||||
Future<SectorModel?> updateSector(SectorModel sector) async {
|
||||
try {
|
||||
final response = await _apiService.put(
|
||||
'${AppKeys.sectorsEndpoint}/${sector.id}',
|
||||
data: sector.toJson(),
|
||||
);
|
||||
final Map<String, dynamic> responseData = response as Map<String, dynamic>;
|
||||
|
||||
if (responseData['status'] == 'success' && responseData['sector'] != null) {
|
||||
final SectorModel updatedSector = SectorModel.fromJson(responseData['sector']);
|
||||
await saveSector(updatedSector);
|
||||
return updatedSector;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer un secteur via l'API
|
||||
Future<bool> deleteSectorFromApi(int id) async {
|
||||
try {
|
||||
final response = await _apiService.delete(
|
||||
'${AppKeys.sectorsEndpoint}/$id',
|
||||
);
|
||||
final Map<String, dynamic> responseData = response as Map<String, dynamic>;
|
||||
|
||||
if (responseData['status'] == 'success') {
|
||||
await deleteSector(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
958
flutt/lib/core/repositories/user_repository.dart
Normal file
958
flutt/lib/core/repositories/user_repository.dart
Normal file
@@ -0,0 +1,958 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:js' as js;
|
||||
import 'package:geosector_app/core/services/hive_web_fix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'package:geosector_app/core/services/sync_service.dart';
|
||||
import 'package:geosector_app/core/data/models/user_model.dart';
|
||||
import 'package:geosector_app/core/data/models/operation_model.dart';
|
||||
import 'package:geosector_app/core/data/models/sector_model.dart';
|
||||
import 'package:geosector_app/core/data/models/passage_model.dart';
|
||||
import 'package:geosector_app/core/data/models/membre_model.dart';
|
||||
import 'package:geosector_app/core/repositories/operation_repository.dart';
|
||||
import 'package:geosector_app/core/repositories/sector_repository.dart';
|
||||
import 'package:geosector_app/core/repositories/passage_repository.dart';
|
||||
import 'package:geosector_app/chat/models/conversation_model.dart';
|
||||
import 'package:geosector_app/chat/models/message_model.dart';
|
||||
|
||||
class UserRepository extends ChangeNotifier {
|
||||
// Utilisation de getters lazy pour n'accéder aux boîtes que lorsque nécessaire
|
||||
Box<UserModel> get _userBox => Hive.box<UserModel>(AppKeys.usersBoxName);
|
||||
|
||||
// Getters pour les autres boîtes qui vérifient si elles sont ouvertes avant accès
|
||||
Box<OperationModel> get _operationBox {
|
||||
_ensureBoxIsOpen(AppKeys.operationsBoxName);
|
||||
return Hive.box<OperationModel>(AppKeys.operationsBoxName);
|
||||
}
|
||||
|
||||
Box<SectorModel> get _sectorBox {
|
||||
_ensureBoxIsOpen(AppKeys.sectorsBoxName);
|
||||
return Hive.box<SectorModel>(AppKeys.sectorsBoxName);
|
||||
}
|
||||
|
||||
// Méthode pour initialiser les boîtes après connexion
|
||||
Future<void> _initializeBoxes() async {
|
||||
debugPrint('Initialisation des boîtes Hive nécessaires...');
|
||||
await _ensureBoxIsOpen(AppKeys.operationsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.sectorsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.passagesBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.membresBoxName);
|
||||
// Les boîtes de chat sont déjà initialisées au démarrage
|
||||
await _ensureBoxIsOpen(AppKeys.chatConversationsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.chatMessagesBoxName);
|
||||
debugPrint('Toutes les boîtes Hive sont maintenant ouvertes');
|
||||
}
|
||||
|
||||
final ApiService _apiService;
|
||||
final SyncService? _syncService;
|
||||
final OperationRepository? _operationRepository;
|
||||
final SectorRepository? _sectorRepository;
|
||||
final PassageRepository? _passageRepository;
|
||||
|
||||
bool _isLoading = false;
|
||||
|
||||
UserRepository(this._apiService,
|
||||
{SyncService? syncService,
|
||||
OperationRepository? operationRepository,
|
||||
SectorRepository? sectorRepository,
|
||||
PassageRepository? passageRepository})
|
||||
: _syncService = syncService,
|
||||
_operationRepository = operationRepository,
|
||||
_sectorRepository = sectorRepository,
|
||||
_passageRepository = passageRepository {
|
||||
// Initialiser la session si un utilisateur est déjà connecté
|
||||
final currentUser = getCurrentUser();
|
||||
if (currentUser != null && currentUser.sessionId != null) {
|
||||
setSessionId(currentUser.sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
// Getters
|
||||
bool get isLoading => _isLoading;
|
||||
bool get isLoggedIn => getCurrentUser() != null;
|
||||
// Vérifie si l'utilisateur a un rôle administrateur (2, 4 ou 9)
|
||||
bool isAdmin() {
|
||||
final user = getCurrentUser();
|
||||
if (user == null) return false;
|
||||
|
||||
final String interface = user.interface ?? 'user';
|
||||
return interface == 'admin';
|
||||
}
|
||||
|
||||
int? get userId => getCurrentUser()?.id;
|
||||
UserModel? get currentUser => getCurrentUser();
|
||||
|
||||
// Récupérer l'utilisateur actuellement connecté
|
||||
UserModel? getCurrentUser() {
|
||||
try {
|
||||
// Chercher un utilisateur avec une session active
|
||||
final activeUsers = _userBox.values
|
||||
.where((user) =>
|
||||
user.sessionId != null && // Vérifier que sessionId n'est pas null
|
||||
user.sessionId!
|
||||
.isNotEmpty && // Vérifier que sessionId n'est pas vide
|
||||
user.sessionExpiry != null &&
|
||||
user.sessionExpiry!.isAfter(DateTime.now()))
|
||||
.toList();
|
||||
|
||||
return activeUsers.isNotEmpty ? activeUsers.first : null;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération de l\'utilisateur actuel: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour le chemin de la page actuelle pour l'utilisateur connecté
|
||||
Future<void> updateLastPath(String path) async {
|
||||
final currentUser = getCurrentUser();
|
||||
if (currentUser != null) {
|
||||
final updatedUser = currentUser.copyWith(lastPath: path);
|
||||
await saveUser(updatedUser);
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer le dernier chemin visité par l'utilisateur
|
||||
String? getLastPath() {
|
||||
final currentUser = getCurrentUser();
|
||||
return currentUser?.lastPath;
|
||||
}
|
||||
|
||||
// Configurer la session dans l'API
|
||||
void setSessionId(String? sessionId) {
|
||||
_apiService.setSessionId(sessionId);
|
||||
}
|
||||
|
||||
// Login API PHP
|
||||
Future<Map<String, dynamic>> loginAPI(String username, String password,
|
||||
{String type = 'admin'}) async {
|
||||
try {
|
||||
return await _apiService.login(username, password, type: type);
|
||||
} catch (e) {
|
||||
debugPrint('Erreur login API: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Register API PHP - Uniquement pour les administrateurs
|
||||
Future<Map<String, dynamic>> registerAPI(String email, String name,
|
||||
String amicaleName, String postalCode, String cityName) async {
|
||||
try {
|
||||
final Map<String, dynamic> data = {
|
||||
'email': email,
|
||||
'name': name,
|
||||
'amicale_name': amicaleName,
|
||||
'postal_code': postalCode,
|
||||
'city_name': cityName
|
||||
};
|
||||
|
||||
final response =
|
||||
await _apiService.post(AppKeys.registerEndpoint, data: data);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur register API: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Logout API PHP
|
||||
Future<void> logoutAPI() async {
|
||||
try {
|
||||
await _apiService.logout();
|
||||
} catch (e) {
|
||||
debugPrint('Erreur logout API: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode d'inscription (uniquement pour les administrateurs)
|
||||
Future<bool> register(String email, String password, String name,
|
||||
String amicaleName, String postalCode, String cityName) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Enregistrer l'administrateur via l'API
|
||||
final apiResult =
|
||||
await registerAPI(email, name, amicaleName, postalCode, cityName);
|
||||
|
||||
// Créer l'administrateur local
|
||||
final int userId = apiResult['user_id'] is String
|
||||
? int.parse(apiResult['user_id'])
|
||||
: apiResult['user_id'];
|
||||
final now = DateTime.now();
|
||||
final newAdmin = UserModel(
|
||||
id: userId,
|
||||
email: email,
|
||||
name: name,
|
||||
role: AppKeys.roleAdmin2,
|
||||
createdAt: now,
|
||||
lastSyncedAt: now,
|
||||
isActive: true,
|
||||
isSynced: true,
|
||||
sessionId: apiResult['session_id'],
|
||||
sessionExpiry: DateTime.parse(apiResult['session_expiry']),
|
||||
);
|
||||
|
||||
// Sauvegarder dans le repository local
|
||||
await saveUser(newAdmin);
|
||||
|
||||
// Configurer la session dans l'API
|
||||
setSessionId(newAdmin.sessionId);
|
||||
|
||||
notifyListeners();
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur d\'inscription: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Login complet
|
||||
Future<bool> login(String username, String password,
|
||||
{String type = 'admin'}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
debugPrint('Début du processus de connexion pour: $username');
|
||||
|
||||
// Supprimer les références aux boîtes non définies dans AppKeys
|
||||
// pour éviter les erreurs de suppression de boîtes non référencées
|
||||
final nonDefinedBoxes = ['auth', 'locations', 'messages'];
|
||||
for (final boxName in nonDefinedBoxes) {
|
||||
try {
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Fermeture de la boîte non référencée: $boxName');
|
||||
await Hive.box(boxName).close();
|
||||
}
|
||||
|
||||
// Supprimer la boîte du disque
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// S'assurer que toutes les Hive boxes sont vides avant de se connecter
|
||||
// Vider toutes les boîtes Hive SAUF la boîte des utilisateurs
|
||||
debugPrint('Nettoyage des données existantes avant connexion...');
|
||||
|
||||
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||
if (kIsWeb) {
|
||||
await HiveWebFix.safeCleanHiveBoxes(
|
||||
excludeBoxes: [AppKeys.usersBoxName]);
|
||||
}
|
||||
// Sur iOS, nettoyer les fichiers Hive directement
|
||||
else if (!kIsWeb && Platform.isIOS) {
|
||||
await _cleanHiveFilesOnIOS();
|
||||
}
|
||||
// Sur Android, nettoyer les fichiers Hive directement
|
||||
else if (!kIsWeb && Platform.isAndroid) {
|
||||
await _cleanHiveFilesOnAndroid();
|
||||
}
|
||||
|
||||
// Nettoyer les boîtes sans les fermer
|
||||
await _clearAndRecreateBoxes();
|
||||
|
||||
// Initialiser les boîtes nécessaires avant d'appeler l'API
|
||||
// Cela garantit que toutes les boîtes sont ouvertes avant le traitement des données
|
||||
await _initializeBoxes();
|
||||
|
||||
// Appeler l'API
|
||||
debugPrint('Appel de l\'API de connexion (type: $type)...');
|
||||
final apiResult = await loginAPI(username, password, type: type);
|
||||
|
||||
// Vérifier le statut de la réponse
|
||||
final status = apiResult['status'] as String?;
|
||||
final message = apiResult['message'] as String?;
|
||||
|
||||
// Si le statut n'est pas 'success', retourner false
|
||||
if (status != 'success') {
|
||||
debugPrint('Échec de connexion: $message');
|
||||
return false;
|
||||
}
|
||||
|
||||
debugPrint('Connexion réussie, traitement des données...');
|
||||
|
||||
// [Reste de la méthode login inchangé...]
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur de connexion: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour vérifier si une boîte est ouverte et l'ouvrir si nécessaire
|
||||
Future<void> _ensureBoxIsOpen(String boxName) async {
|
||||
try {
|
||||
if (!Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Ouverture de la boîte $boxName...');
|
||||
if (boxName == AppKeys.passagesBoxName) {
|
||||
await Hive.openBox<PassageModel>(boxName);
|
||||
} else if (boxName == AppKeys.operationsBoxName) {
|
||||
await Hive.openBox<OperationModel>(boxName);
|
||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
||||
await Hive.openBox<SectorModel>(boxName);
|
||||
} else if (boxName == AppKeys.usersBoxName) {
|
||||
await Hive.openBox<UserModel>(boxName);
|
||||
} else if (boxName == AppKeys.membresBoxName) {
|
||||
await Hive.openBox<MembreModel>(boxName);
|
||||
} else if (boxName == AppKeys.settingsBoxName) {
|
||||
await Hive.openBox(boxName);
|
||||
} else if (boxName == AppKeys.chatConversationsBoxName) {
|
||||
await Hive.openBox<ConversationModel>(boxName);
|
||||
} else if (boxName == AppKeys.chatMessagesBoxName) {
|
||||
await Hive.openBox<MessageModel>(boxName);
|
||||
} else {
|
||||
await Hive.openBox(boxName);
|
||||
}
|
||||
// Boîte ouverte avec succès
|
||||
} else {
|
||||
// La boîte est déjà ouverte
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de l\'ouverture de la boîte $boxName: $e');
|
||||
throw Exception('Impossible d\'ouvrir la boîte $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour vider et recréer toutes les boîtes Hive sauf la boîte des utilisateurs
|
||||
Future<void> _clearAndRecreateBoxes() async {
|
||||
try {
|
||||
debugPrint('Début de la suppression complète des données Hive...');
|
||||
|
||||
// Supprimer les références aux boîtes non définies dans AppKeys
|
||||
// pour éviter les erreurs de suppression de boîtes non référencées
|
||||
final nonDefinedBoxes = ['auth', 'locations', 'messages'];
|
||||
for (final boxName in nonDefinedBoxes) {
|
||||
try {
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Fermeture de la boîte non référencée: $boxName');
|
||||
await Hive.box(boxName).close();
|
||||
}
|
||||
|
||||
// Supprimer la boîte du disque
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||
if (kIsWeb) {
|
||||
await HiveWebFix.safeCleanHiveBoxes(
|
||||
excludeBoxes: [AppKeys.usersBoxName]);
|
||||
}
|
||||
// Sur iOS, nettoyer les fichiers Hive directement
|
||||
else if (Platform.isIOS) {
|
||||
await _cleanHiveFilesOnIOS();
|
||||
}
|
||||
// Sur Android, nettoyer les fichiers Hive directement
|
||||
else if (Platform.isAndroid) {
|
||||
await _cleanHiveFilesOnAndroid();
|
||||
}
|
||||
|
||||
// Liste des noms de boîtes à supprimer
|
||||
final boxesToDelete = [
|
||||
AppKeys.passagesBoxName,
|
||||
AppKeys.operationsBoxName,
|
||||
AppKeys.sectorsBoxName,
|
||||
AppKeys.chatConversationsBoxName,
|
||||
AppKeys.chatMessagesBoxName,
|
||||
];
|
||||
|
||||
// Vider chaque boîte sans la fermer
|
||||
for (final boxName in boxesToDelete) {
|
||||
try {
|
||||
debugPrint('Nettoyage de la boîte: $boxName');
|
||||
|
||||
// Vérifier si la boîte est déjà ouverte
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
// Vider la boîte sans la fermer
|
||||
debugPrint('Boîte $boxName déjà ouverte, vidage sans fermeture');
|
||||
if (boxName == AppKeys.passagesBoxName) {
|
||||
await Hive.box<PassageModel>(boxName).clear();
|
||||
} else if (boxName == AppKeys.operationsBoxName) {
|
||||
await Hive.box<OperationModel>(boxName).clear();
|
||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
||||
await Hive.box<SectorModel>(boxName).clear();
|
||||
} else if (boxName == AppKeys.chatConversationsBoxName) {
|
||||
await Hive.box<ConversationModel>(boxName).clear();
|
||||
} else if (boxName == AppKeys.chatMessagesBoxName) {
|
||||
await Hive.box<MessageModel>(boxName).clear();
|
||||
}
|
||||
} else {
|
||||
// Supprimer la boîte du disque si elle n'est pas ouverte
|
||||
debugPrint('Boîte $boxName non ouverte, suppression du disque');
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du nettoyage de la boîte $boxName: $e');
|
||||
// Tenter de supprimer la boîte du disque en cas d'erreur
|
||||
try {
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
} catch (deleteError) {
|
||||
debugPrint(
|
||||
'Impossible de supprimer la boîte $boxName: $deleteError');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attendre un court instant pour s'assurer que les opérations de suppression sont terminées
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
// Recréer les boîtes avec la méthode sécurisée
|
||||
debugPrint('Recréation des boîtes Hive...');
|
||||
|
||||
// Utiliser notre méthode pour s'assurer que les boîtes sont ouvertes
|
||||
try {
|
||||
// Passages
|
||||
await _ensureBoxIsOpen(AppKeys.passagesBoxName);
|
||||
|
||||
// Opérations
|
||||
await _ensureBoxIsOpen(AppKeys.operationsBoxName);
|
||||
|
||||
// Secteurs
|
||||
await _ensureBoxIsOpen(AppKeys.sectorsBoxName);
|
||||
|
||||
// Chat
|
||||
await _ensureBoxIsOpen(AppKeys.chatConversationsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.chatMessagesBoxName);
|
||||
|
||||
// Vérifier l'intégrité des boîtes après recréation
|
||||
await _verifyHiveBoxesIntegrity();
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la recréation des boîtes Hive: $e');
|
||||
// Tentative de récupération sur erreur
|
||||
if (kIsWeb) {
|
||||
debugPrint('Tentative de récupération sur le web...');
|
||||
await HiveWebFix.resetHiveCompletely();
|
||||
|
||||
// Réessayer d'ouvrir les boîtes
|
||||
await _ensureBoxIsOpen(AppKeys.passagesBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.operationsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.sectorsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.chatConversationsBoxName);
|
||||
await _ensureBoxIsOpen(AppKeys.chatMessagesBoxName);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la réinitialisation des boîtes Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour vérifier l'intégrité des boîtes Hive après recréation
|
||||
Future<void> _verifyHiveBoxesIntegrity() async {
|
||||
try {
|
||||
debugPrint('Vérification de l\'intégrité des boîtes Hive...');
|
||||
|
||||
// Liste des boîtes à vérifier avec leur type
|
||||
final boxesToCheck = [
|
||||
{'name': AppKeys.passagesBoxName, 'type': 'passage'},
|
||||
{'name': AppKeys.operationsBoxName, 'type': 'operation'},
|
||||
{'name': AppKeys.sectorsBoxName, 'type': 'sector'},
|
||||
{'name': AppKeys.chatConversationsBoxName, 'type': 'conversation'},
|
||||
{'name': AppKeys.chatMessagesBoxName, 'type': 'message'},
|
||||
];
|
||||
|
||||
// Vérifier chaque boîte
|
||||
for (final boxInfo in boxesToCheck) {
|
||||
final boxName = boxInfo['name'] as String;
|
||||
final boxType = boxInfo['type'] as String;
|
||||
|
||||
try {
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
// Utiliser une approche spécifique au type pour éviter les erreurs de typage
|
||||
Box box;
|
||||
try {
|
||||
if (boxType == 'passage') {
|
||||
box = Hive.box<PassageModel>(boxName);
|
||||
} else if (boxType == 'operation') {
|
||||
box = Hive.box<OperationModel>(boxName);
|
||||
} else if (boxType == 'sector') {
|
||||
box = Hive.box<SectorModel>(boxName);
|
||||
} else if (boxType == 'conversation') {
|
||||
box = Hive.box<ConversationModel>(boxName);
|
||||
} else if (boxType == 'message') {
|
||||
box = Hive.box<MessageModel>(boxName);
|
||||
} else {
|
||||
box = Hive.box(boxName);
|
||||
}
|
||||
|
||||
final count = box.length;
|
||||
debugPrint('Boîte $boxName: $count éléments');
|
||||
|
||||
// Si la boîte contient des éléments, c'est anormal après recréation
|
||||
if (count > 0) {
|
||||
debugPrint(
|
||||
'ATTENTION: La boîte $boxName contient encore des données après recréation');
|
||||
// Essayer de vider la boîte une dernière fois
|
||||
await box.clear();
|
||||
debugPrint('Vidage forcé de la boîte $boxName effectué');
|
||||
}
|
||||
} catch (typeError) {
|
||||
debugPrint(
|
||||
'Erreur de typage lors de la vérification de $boxName: $typeError');
|
||||
|
||||
// Tentative alternative sans typage spécifique
|
||||
try {
|
||||
box = Hive.box(boxName);
|
||||
final count = box.length;
|
||||
debugPrint('Boîte $boxName (sans typage): $count éléments');
|
||||
|
||||
if (count > 0) {
|
||||
await box.clear();
|
||||
debugPrint(
|
||||
'Vidage forcé de la boîte $boxName (sans typage) effectué');
|
||||
}
|
||||
} catch (e2) {
|
||||
debugPrint(
|
||||
'Impossible de vérifier la boîte $boxName même sans typage: $e2');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugPrint(
|
||||
'Boîte $boxName non ouverte, impossible de vérifier l\'intégrité');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la vérification de la boîte $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint('Vérification d\'intégrité terminée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la vérification d\'intégrité des boîtes Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode spéciale pour nettoyer IndexedDB sur le web
|
||||
Future<void> _clearIndexedDB() async {
|
||||
if (kIsWeb) {
|
||||
try {
|
||||
debugPrint('Nettoyage complet d\'IndexedDB sur le web...');
|
||||
// Utiliser JavaScript pour nettoyer IndexedDB
|
||||
js.context.callMethod('eval', [
|
||||
'''
|
||||
var request = indexedDB.deleteDatabase("geosector_app");
|
||||
request.onsuccess = function() { console.log("IndexedDB nettoyé avec succès"); };
|
||||
request.onerror = function() { console.log("Erreur lors du nettoyage d\'IndexedDB"); };
|
||||
'''
|
||||
]);
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
debugPrint('Nettoyage d\'IndexedDB terminé');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du nettoyage d\'IndexedDB: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode spéciale pour nettoyer les fichiers Hive sur iOS
|
||||
Future<void> _cleanHiveFilesOnIOS() async {
|
||||
if (!kIsWeb && Platform.isIOS) {
|
||||
try {
|
||||
debugPrint('Nettoyage des fichiers Hive sur iOS...');
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final hiveDir = Directory('${appDir.path}/hive');
|
||||
|
||||
if (await hiveDir.exists()) {
|
||||
debugPrint('Suppression du répertoire Hive: ${hiveDir.path}');
|
||||
// Exclure le dossier des utilisateurs pour conserver les informations de session
|
||||
final entries = await hiveDir.list().toList();
|
||||
for (var entry in entries) {
|
||||
final name = entry.path.split('/').last;
|
||||
// Ne pas supprimer la boîte des utilisateurs
|
||||
if (!name.contains(AppKeys.usersBoxName)) {
|
||||
debugPrint('Suppression de: ${entry.path}');
|
||||
if (entry is Directory) {
|
||||
await entry.delete(recursive: true);
|
||||
} else if (entry is File) {
|
||||
await entry.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
debugPrint('Nettoyage des fichiers Hive sur iOS terminé');
|
||||
} else {
|
||||
debugPrint('Répertoire Hive non trouvé');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du nettoyage des fichiers Hive sur iOS: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode spéciale pour nettoyer les fichiers Hive sur Android
|
||||
Future<void> _cleanHiveFilesOnAndroid() async {
|
||||
if (!kIsWeb && Platform.isAndroid) {
|
||||
try {
|
||||
debugPrint('Nettoyage des fichiers Hive sur Android...');
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final hiveDir = Directory('${appDir.path}');
|
||||
|
||||
if (await hiveDir.exists()) {
|
||||
debugPrint('Recherche des fichiers Hive dans: ${hiveDir.path}');
|
||||
// Sur Android, les fichiers Hive sont directement dans le répertoire de l'application
|
||||
final entries = await hiveDir.list().toList();
|
||||
int filesDeleted = 0;
|
||||
|
||||
for (var entry in entries) {
|
||||
final name = entry.path.split('/').last;
|
||||
// Ne supprimer que les fichiers Hive, mais pas la boîte des utilisateurs
|
||||
if (name.endsWith('.hive') &&
|
||||
!name.contains(AppKeys.usersBoxName)) {
|
||||
debugPrint('Suppression du fichier Hive: ${entry.path}');
|
||||
if (entry is File) {
|
||||
await entry.delete();
|
||||
filesDeleted++;
|
||||
|
||||
// Supprimer également les fichiers lock associés
|
||||
final lockFile = File('${entry.path}.lock');
|
||||
if (await lockFile.exists()) {
|
||||
await lockFile.delete();
|
||||
debugPrint('Suppression du fichier lock: ${lockFile.path}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'Nettoyage des fichiers Hive sur Android terminé. $filesDeleted fichiers supprimés.');
|
||||
} else {
|
||||
debugPrint('Répertoire d\'application non trouvé');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors du nettoyage des fichiers Hive sur Android: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logout complet
|
||||
Future<bool> logout() async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
debugPrint('Début du processus de déconnexion...');
|
||||
|
||||
// S'assurer que la boîte des utilisateurs est ouverte avant tout
|
||||
await _ensureBoxIsOpen(AppKeys.usersBoxName);
|
||||
|
||||
// Supprimer les références aux boîtes non définies dans AppKeys
|
||||
final nonDefinedBoxes = ['auth', 'locations', 'messages'];
|
||||
for (final boxName in nonDefinedBoxes) {
|
||||
try {
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Fermeture de la boîte non référencée: $boxName');
|
||||
await Hive.box(boxName).close();
|
||||
}
|
||||
|
||||
// Supprimer la boîte du disque
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer l'utilisateur actuel avant de nettoyer les données
|
||||
final currentUser = getCurrentUser();
|
||||
if (currentUser == null) {
|
||||
debugPrint('Aucun utilisateur connecté, déconnexion terminée');
|
||||
return true;
|
||||
}
|
||||
|
||||
debugPrint('Déconnexion de l\'utilisateur: ${currentUser.email}');
|
||||
|
||||
// Appeler l'API pour déconnecter la session
|
||||
if (currentUser.sessionId != null) {
|
||||
debugPrint('Déconnexion de la session API...');
|
||||
await logoutAPI();
|
||||
}
|
||||
|
||||
// Effacer la session de l'utilisateur
|
||||
debugPrint('Mise à jour de l\'utilisateur pour effacer la session...');
|
||||
final updatedUser = currentUser.copyWith(
|
||||
sessionId: null,
|
||||
sessionExpiry: null,
|
||||
lastPath:
|
||||
null, // Réinitialiser le chemin pour revenir à l'écran de connexion
|
||||
);
|
||||
|
||||
// Sauvegarder l'utilisateur sans session
|
||||
await saveUser(updatedUser);
|
||||
|
||||
// Effacer la session de l'API
|
||||
setSessionId(null);
|
||||
|
||||
// Maintenant, nettoyer les données
|
||||
debugPrint('Nettoyage des données...');
|
||||
|
||||
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||
if (kIsWeb) {
|
||||
await HiveWebFix.safeCleanHiveBoxes(
|
||||
excludeBoxes: [AppKeys.usersBoxName]);
|
||||
}
|
||||
// Sur iOS, nettoyer les fichiers Hive directement
|
||||
else if (!kIsWeb && Platform.isIOS) {
|
||||
await _cleanHiveFilesOnIOS();
|
||||
}
|
||||
// Sur Android, nettoyer les fichiers Hive directement
|
||||
else if (!kIsWeb && Platform.isAndroid) {
|
||||
await _cleanHiveFilesOnAndroid();
|
||||
}
|
||||
|
||||
// Vider les boîtes sans les fermer, y compris les boîtes de chat
|
||||
debugPrint('Suppression des données Hive...');
|
||||
await _clearAndRecreateBoxes();
|
||||
|
||||
// Vider spécifiquement les boîtes de chat si elles sont ouvertes
|
||||
try {
|
||||
if (Hive.isBoxOpen(AppKeys.chatConversationsBoxName)) {
|
||||
await Hive.box<ConversationModel>(AppKeys.chatConversationsBoxName).clear();
|
||||
debugPrint('Boîte conversations vidée');
|
||||
}
|
||||
if (Hive.isBoxOpen(AppKeys.chatMessagesBoxName)) {
|
||||
await Hive.box<MessageModel>(AppKeys.chatMessagesBoxName).clear();
|
||||
debugPrint('Boîte messages vidée');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du vidage des boîtes de chat: $e');
|
||||
}
|
||||
|
||||
debugPrint('Déconnexion terminée avec succès');
|
||||
|
||||
notifyListeners();
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur de déconnexion: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Obtenir tous les utilisateurs locaux
|
||||
List<UserModel> getAllUsers() {
|
||||
return _userBox.values.toList();
|
||||
}
|
||||
|
||||
// Obtenir un utilisateur par son ID
|
||||
UserModel? getUserById(int id) {
|
||||
return _userBox.get(id);
|
||||
}
|
||||
|
||||
// Obtenir un utilisateur par son email
|
||||
UserModel? getUserByEmail(String email) {
|
||||
try {
|
||||
return _userBox.values.firstWhere(
|
||||
(user) => user.email == email,
|
||||
);
|
||||
} catch (e) {
|
||||
return null; // Utilisateur non trouvé
|
||||
}
|
||||
}
|
||||
|
||||
// Créer ou mettre à jour un utilisateur localement
|
||||
Future<UserModel> saveUser(UserModel user) async {
|
||||
await _userBox.put(user.id, user);
|
||||
notifyListeners(); // Notifier les changements pour mettre à jour l'UI
|
||||
return user;
|
||||
}
|
||||
|
||||
// Supprimer un utilisateur localement
|
||||
Future<void> deleteUser(String id) async {
|
||||
await _userBox.delete(id);
|
||||
}
|
||||
|
||||
// Créer un nouvel utilisateur localement et tenter de le synchroniser
|
||||
Future<UserModel> createUser({
|
||||
required String email,
|
||||
required String name,
|
||||
required int role,
|
||||
}) async {
|
||||
// Générer un ID numérique temporaire (timestamp)
|
||||
final int tempId = DateTime.now().millisecondsSinceEpoch;
|
||||
final now = DateTime.now();
|
||||
|
||||
final user = UserModel(
|
||||
id: tempId,
|
||||
email: email,
|
||||
name: name,
|
||||
role: role,
|
||||
createdAt: now,
|
||||
lastSyncedAt: now,
|
||||
isSynced: false,
|
||||
);
|
||||
|
||||
await _userBox.put(user.id, user);
|
||||
|
||||
// Tenter de synchroniser si possible
|
||||
await syncUser(user);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
// Synchroniser un utilisateur spécifique avec le serveur
|
||||
Future<UserModel> syncUser(UserModel user) async {
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
|
||||
if (!hasConnection) {
|
||||
return user;
|
||||
}
|
||||
|
||||
UserModel syncedUser;
|
||||
|
||||
if (!user.isSynced) {
|
||||
// Si l'utilisateur n'est pas encore synchronisé, le créer sur le serveur
|
||||
syncedUser = await _apiService.createUser(user);
|
||||
} else {
|
||||
// Sinon, mettre à jour les informations
|
||||
syncedUser = await _apiService.updateUser(user);
|
||||
}
|
||||
|
||||
// Mettre à jour l'utilisateur local avec les informations du serveur
|
||||
final updatedUser = syncedUser.copyWith(
|
||||
isSynced: true,
|
||||
lastSyncedAt: DateTime.now(),
|
||||
);
|
||||
|
||||
await _userBox.put(updatedUser.id, updatedUser);
|
||||
return updatedUser;
|
||||
} catch (e) {
|
||||
// En cas d'erreur, garder l'utilisateur local tel quel
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
// Synchroniser tous les utilisateurs non synchronisés
|
||||
Future<void> syncAllUsers() async {
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
|
||||
if (!hasConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
final unsyncedUsers =
|
||||
_userBox.values.where((user) => !user.isSynced).toList();
|
||||
|
||||
if (unsyncedUsers.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Synchroniser en batch
|
||||
final result = await _apiService.syncData(users: unsyncedUsers);
|
||||
|
||||
// Mettre à jour les utilisateurs locaux
|
||||
if (result['users'] != null) {
|
||||
for (final userData in result['users']) {
|
||||
final syncedUser = UserModel.fromJson(userData);
|
||||
await _userBox.put(
|
||||
syncedUser.id,
|
||||
syncedUser.copyWith(
|
||||
isSynced: true,
|
||||
lastSyncedAt: DateTime.now(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Gérer les erreurs de synchronisation
|
||||
print('Erreur de synchronisation des utilisateurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Rafraîchir les données depuis le serveur
|
||||
Future<void> refreshFromServer() async {
|
||||
try {
|
||||
final hasConnection = await _apiService.hasInternetConnection();
|
||||
|
||||
if (!hasConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Récupérer tous les utilisateurs du serveur
|
||||
final serverUsers = await _apiService.getUsers();
|
||||
|
||||
// Mettre à jour la base locale
|
||||
for (final serverUser in serverUsers) {
|
||||
final updatedUser = serverUser.copyWith(
|
||||
isSynced: true,
|
||||
lastSyncedAt: DateTime.now(),
|
||||
);
|
||||
await _userBox.put(updatedUser.id, updatedUser);
|
||||
}
|
||||
} catch (e) {
|
||||
// Gérer les erreurs
|
||||
print('Erreur lors du rafraîchissement des données: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Synchroniser les données utilisateur
|
||||
Future<void> syncUserData() async {
|
||||
if (_syncService != null && currentUser != null) {
|
||||
await _syncService!.syncUserData(currentUser!.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer la dernière opération active (avec isActive == true)
|
||||
OperationModel? getCurrentOperation() {
|
||||
try {
|
||||
// Récupérer toutes les opérations
|
||||
final operations = _operationBox.values.toList();
|
||||
|
||||
// Filtrer pour ne garder que les opérations actives
|
||||
final activeOperations = operations.where((op) => op.isActive).toList();
|
||||
|
||||
// Si aucune opération active n'est trouvée, retourner null
|
||||
if (activeOperations.isEmpty) {
|
||||
return operations.isNotEmpty ? operations.last : null;
|
||||
}
|
||||
|
||||
// Retourner la dernière opération active
|
||||
return activeOperations.last;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération de l\'opération actuelle: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer tous les secteurs de l'utilisateur
|
||||
List<SectorModel> getUserSectors() {
|
||||
try {
|
||||
return _sectorBox.values.toList();
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération des secteurs: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer un secteur par son ID
|
||||
SectorModel? getSectorById(int id) {
|
||||
try {
|
||||
return _sectorBox.get(id);
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération du secteur: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user