From 7cfc5eab6be8bfea21600cdd90ea2cd44e7faf7e Mon Sep 17 00:00:00 2001 From: Dayron Date: Thu, 23 Oct 2025 11:03:11 +0200 Subject: [PATCH] feat: Refactor account handling and improve group creation logic --- lib/blocs/group/group_bloc.dart | 6 +- lib/components/home/create_trip_content.dart | 42 ++----------- lib/components/home/home_content.dart | 4 +- lib/models/account.dart | 36 ++++++----- lib/models/settlement.dart | 4 +- lib/repositories/account_repository.dart | 65 ++++++++++++++++++-- lib/services/account_service.dart | 6 +- 7 files changed, 97 insertions(+), 66 deletions(-) diff --git a/lib/blocs/group/group_bloc.dart b/lib/blocs/group/group_bloc.dart index b0406d2..1ecdc8c 100644 --- a/lib/blocs/group/group_bloc.dart +++ b/lib/blocs/group/group_bloc.dart @@ -96,11 +96,11 @@ class GroupBloc extends Bloc { ) async { try { emit(GroupLoading()); - await _repository.createGroupWithMembers( + final groupId = await _repository.createGroupWithMembers( group: event.group, members: event.members, ); - emit(const GroupOperationSuccess('Groupe créé avec succès')); + emit(GroupCreated(groupId: groupId)); } catch (e) { emit(GroupError('Erreur lors de la création: $e')); } @@ -111,7 +111,6 @@ class GroupBloc extends Bloc { Emitter emit, ) async { try { - // CORRECTION : Utiliser addMemberToGroup au lieu de addMember await _repository.addMember(event.groupId, event.member); emit(const GroupOperationSuccess('Membre ajouté')); } catch (e) { @@ -124,7 +123,6 @@ class GroupBloc extends Bloc { Emitter emit, ) async { try { - // CORRECTION : Utiliser removeMemberFromGroup au lieu de removeMember await _repository.removeMember(event.groupId, event.userId); emit(const GroupOperationSuccess('Membre supprimé')); } catch (e) { diff --git a/lib/components/home/create_trip_content.dart b/lib/components/home/create_trip_content.dart index 7604cd3..66aa14e 100644 --- a/lib/components/home/create_trip_content.dart +++ b/lib/components/home/create_trip_content.dart @@ -9,7 +9,6 @@ import '../../blocs/trip/trip_event.dart'; import '../../blocs/trip/trip_state.dart'; import '../../blocs/group/group_bloc.dart'; import '../../blocs/group/group_event.dart'; -import '../../blocs/group/group_state.dart'; import '../../blocs/account/account_bloc.dart'; import '../../blocs/account/account_event.dart'; import '../../models/account.dart'; @@ -111,15 +110,13 @@ class _CreateTripContentState extends State { @override Widget build(BuildContext context) { - return MultiBlocListener( - listeners: [ - // Listener pour TripBloc - BlocListener( + return BlocListener( listener: (context, tripState) { if (tripState is TripCreated) { // Stocker l'ID du trip et créer le groupe _createdTripId = tripState.tripId; - _createGroupForTrip(tripState.tripId); + _createGroupForTrip(_createdTripId!); + _createAccountForTrip(_createdTripId!); } else if (tripState is TripOperationSuccess) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( @@ -147,31 +144,7 @@ class _CreateTripContentState extends State { } } }, - ), - // Nouveau listener pour GroupBloc - BlocListener( - listener: (context, groupState) { - if (groupState is GroupCreated && _createdTripId != null) { - // Le groupe a été créé, maintenant créer le compte - print('++++++++++++++ Creating account for trip ${_createdTripId!} and group ${groupState.groupId} ++++++++++++++'); - _createAccountForTrip(_createdTripId!, groupState.groupId); - } else if (groupState is GroupError) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Erreur lors de la création du groupe: ${groupState.message}'), - backgroundColor: Colors.red, - ), - ); - setState(() { - _isLoading = false; - }); - } - } - }, - ), - ], - child: BlocBuilder( + child: BlocBuilder( builder: (context, userState) { if (userState is! user_state.UserLoaded) { return Scaffold( @@ -661,18 +634,15 @@ class _CreateTripContentState extends State { } } - Future _createAccountForTrip(String tripId, String groupId) async { + Future _createAccountForTrip(String tripId) async { final accountBloc = context.read(); try { final userState = context.read().state; if (userState is! user_state.UserLoaded) return; - print('Creating account for trip $tripId and group $groupId'); - final account = Account( id: '', tripId: tripId, - groupId: groupId, name: _titleController.text.trim(), ); @@ -683,8 +653,6 @@ class _CreateTripContentState extends State { members: accountsMembers, )); - print('++++++++++++++ Created account for trip $tripId and group $groupId ++++++++++++++'); - if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( diff --git a/lib/components/home/home_content.dart b/lib/components/home/home_content.dart index 7391ba5..188db61 100644 --- a/lib/components/home/home_content.dart +++ b/lib/components/home/home_content.dart @@ -157,13 +157,15 @@ class _HomeContentState extends State with AutomaticKeepAliveClient ), floatingActionButton: FloatingActionButton( onPressed: () async { + final tripBloc = context.read(); + final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => const CreateTripContent()), ); if (result == true && mounted) { - context.read().add(LoadTripsByUserId(userId: user.id)); + tripBloc.add(LoadTripsByUserId(userId: user.id)); } }, backgroundColor: Theme.of(context).colorScheme.primary, diff --git a/lib/models/account.dart b/lib/models/account.dart index 3e74cc7..6cc5afa 100644 --- a/lib/models/account.dart +++ b/lib/models/account.dart @@ -1,53 +1,61 @@ +import 'dart:convert'; import 'group_member.dart'; class Account { final String id; final String tripId; - final String groupId; final String name; + final DateTime createdAt; + final DateTime updatedAt; final List members; Account({ required this.id, required this.tripId, - required this.groupId, required this.name, + DateTime? createdAt, + DateTime? updatedAt, List? members, - }) : members = members ?? []; + }) : createdAt = createdAt ?? DateTime.now(), + updatedAt = updatedAt ?? DateTime.now(), + members = members ?? []; - - factory Account.fromMap(Map map) { + factory Account.fromMap(Map map, String id) { return Account( - id: map['id'] as String, - tripId: map['tripId'] as String, - groupId: map['groupId'] as String, - name: map['name'] as String, + id: id, + tripId: map['tripId'] ?? '', + name: map['name'] ?? '', + createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] ?? 0), + updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] ?? 0), members: [], ); } Map toMap() { return { - 'id': id, 'tripId': tripId, - 'groupId': groupId, 'name': name, - 'members': members.map((member) => member.toMap()).toList(), + 'createdAt': createdAt.millisecondsSinceEpoch, + 'updatedAt': updatedAt.millisecondsSinceEpoch, }; } + String toJson() => json.encode(toMap()); + Account copyWith({ String? id, String? tripId, - String? groupId, String? name, + DateTime? createdAt, + DateTime? updatedAt, List? members, }) { return Account( id: id ?? this.id, tripId: tripId ?? this.tripId, - groupId: groupId ?? this.groupId, name: name ?? this.name, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, members: members ?? this.members, ); } diff --git a/lib/models/settlement.dart b/lib/models/settlement.dart index ec9de30..842b563 100644 --- a/lib/models/settlement.dart +++ b/lib/models/settlement.dart @@ -93,7 +93,7 @@ class Settlement extends Equatable { String get formattedAmount => '${amount.toStringAsFixed(2)} €'; - String get description => '$fromUserName doit ${formattedAmount} à $toUserName'; + String get description => '$fromUserName doit $formattedAmount à $toUserName'; String get shortDescription => '$fromUserName → $toUserName'; @@ -125,6 +125,6 @@ class Settlement extends Equatable { @override String toString() { - return 'Settlement(${shortDescription}: ${formattedAmount}, status: $status)'; + return 'Settlement($shortDescription: $formattedAmount, status: $status)'; } } \ No newline at end of file diff --git a/lib/repositories/account_repository.dart b/lib/repositories/account_repository.dart index c7f4c74..16ef55a 100644 --- a/lib/repositories/account_repository.dart +++ b/lib/repositories/account_repository.dart @@ -54,9 +54,8 @@ class AccountRepository { .get(); if (memberDoc.exists) { final accountData = accountDoc.data() as Map; - final account = Account.fromMap(accountData); + final account = Account.fromMap(accountData, accountId); // ✅ Ajout de l'ID final members = await getAccountMembers(accountId); - userAccounts.add(account.copyWith(members: members)); } else { _errorService.logInfo('account_repository.dart', 'Utilisateur NON membre de $accountId'); @@ -99,15 +98,44 @@ class AccountRepository { } } - Future getAccountById(String accountId) async { - return await _firestore.collection('accounts').doc(accountId).get(); + Future getAccountById(String accountId) async { + try { + final doc = await _firestore.collection('accounts').doc(accountId).get(); + if (doc.exists) { + return Account.fromMap(doc.data() as Map, doc.id); + } + return null; + } catch (e) { + throw Exception('Erreur lors de la récupération du compte: $e'); + } + } + + Future getAccountByTripId(String tripId) async { + try { + final querySnapshot = await _firestore + .collection('accounts') + .where('tripId', isEqualTo: tripId) + .limit(1) + .get(); + + if (querySnapshot.docs.isNotEmpty) { + final doc = querySnapshot.docs.first; + return Account.fromMap(doc.data(), doc.id); + } + return null; + } catch (e) { + throw Exception('Erreur lors de la récupération du compte: $e'); + } } Future updateAccount(String accountId, Account account) async { try { - await _firestore.collection('accounts').doc(accountId).update(account.toMap()); + // Mettre à jour la date de modification + final updatedAccount = account.copyWith(updatedAt: DateTime.now()); + await _firestore.collection('accounts').doc(accountId).update(updatedAccount.toMap()); } catch (e) { _errorService.logError('account_repository.dart', 'Erreur lors de la mise à jour du compte: $e'); + throw Exception('Erreur lors de la mise à jour du compte: $e'); } } @@ -123,13 +151,17 @@ class AccountRepository { final docId = querySnapshot.docs.first.id; + // Supprimer tous les membres final membersSnapshot = await _membersCollection(docId).get(); for (var memberDoc in membersSnapshot.docs) { await _membersCollection(docId).doc(memberDoc.id).delete(); } + + // Supprimer le compte await _accountCollection.doc(docId).delete(); } catch (e) { _errorService.logError('account_repository.dart', 'Erreur lors de la suppression du compte: $e'); + throw Exception('Erreur lors de la suppression du compte: $e'); } } @@ -143,4 +175,27 @@ class AccountRepository { .toList(), ); } + + Stream watchAccount(String accountId) { + return _accountCollection.doc(accountId).snapshots().map((doc) { + if (doc.exists) { + return Account.fromMap(doc.data() as Map, doc.id); + } + return null; + }); + } + + Stream watchAccountByTripId(String tripId) { + return _accountCollection + .where('tripId', isEqualTo: tripId) + .limit(1) + .snapshots() + .map((snapshot) { + if (snapshot.docs.isNotEmpty) { + final doc = snapshot.docs.first; + return Account.fromMap(doc.data() as Map, doc.id); + } + return null; + }); + } } \ No newline at end of file diff --git a/lib/services/account_service.dart b/lib/services/account_service.dart index 3b9eed4..3c4e0ce 100644 --- a/lib/services/account_service.dart +++ b/lib/services/account_service.dart @@ -9,7 +9,7 @@ class AccountService { Stream> getAccountsStream() { return _firestore.collection('accounts').snapshots().map((snapshot) { return snapshot.docs.map((doc) { - return Account.fromMap(doc.data()); + return Account.fromMap(doc.data(), doc.id); }).toList(); }); } @@ -52,8 +52,8 @@ class AccountService { .snapshots() .map((snapshot) { return snapshot.docs.map((doc) { - final account = Account.fromMap(doc.data()); - _errorService.logError('Compte: ${account.name}, Membres: ${account.members.length}', StackTrace.current); + final account = Account.fromMap(doc.data(), doc.id); + _errorService.logError('Compte: ${account.name}', StackTrace.current); return account; }).toList(); });