feat: Refactor account handling and improve group creation logic

This commit is contained in:
Dayron
2025-10-23 11:03:11 +02:00
parent 905948379a
commit 7cfc5eab6b
7 changed files with 97 additions and 66 deletions

View File

@@ -96,11 +96,11 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
) 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<GroupEvent, GroupState> {
Emitter<GroupState> 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<GroupEvent, GroupState> {
Emitter<GroupState> emit,
) async {
try {
// CORRECTION : Utiliser removeMemberFromGroup au lieu de removeMember
await _repository.removeMember(event.groupId, event.userId);
emit(const GroupOperationSuccess('Membre supprimé'));
} catch (e) {

View File

@@ -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<CreateTripContent> {
@override
Widget build(BuildContext context) {
return MultiBlocListener(
listeners: [
// Listener pour TripBloc
BlocListener<TripBloc, TripState>(
return BlocListener<TripBloc, TripState>(
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<CreateTripContent> {
}
}
},
),
// Nouveau listener pour GroupBloc
BlocListener<GroupBloc, GroupState>(
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<UserBloc, user_state.UserState>(
child: BlocBuilder<UserBloc, user_state.UserState>(
builder: (context, userState) {
if (userState is! user_state.UserLoaded) {
return Scaffold(
@@ -661,18 +634,15 @@ class _CreateTripContentState extends State<CreateTripContent> {
}
}
Future<void> _createAccountForTrip(String tripId, String groupId) async {
Future<void> _createAccountForTrip(String tripId) async {
final accountBloc = context.read<AccountBloc>();
try {
final userState = context.read<UserBloc>().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<CreateTripContent> {
members: accountsMembers,
));
print('++++++++++++++ Created account for trip $tripId and group $groupId ++++++++++++++');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(

View File

@@ -157,13 +157,15 @@ class _HomeContentState extends State<HomeContent> with AutomaticKeepAliveClient
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final tripBloc = context.read<TripBloc>();
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const CreateTripContent()),
);
if (result == true && mounted) {
context.read<TripBloc>().add(LoadTripsByUserId(userId: user.id));
tripBloc.add(LoadTripsByUserId(userId: user.id));
}
},
backgroundColor: Theme.of(context).colorScheme.primary,

View File

@@ -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<GroupMember> members;
Account({
required this.id,
required this.tripId,
required this.groupId,
required this.name,
DateTime? createdAt,
DateTime? updatedAt,
List<GroupMember>? members,
}) : members = members ?? [];
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now(),
members = members ?? [];
factory Account.fromMap(Map<String, dynamic> map) {
factory Account.fromMap(Map<String, dynamic> 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<String, dynamic> 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<GroupMember>? 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,
);
}

View File

@@ -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)';
}
}

View File

@@ -54,9 +54,8 @@ class AccountRepository {
.get();
if (memberDoc.exists) {
final accountData = accountDoc.data() as Map<String, dynamic>;
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<DocumentSnapshot> getAccountById(String accountId) async {
return await _firestore.collection('accounts').doc(accountId).get();
Future<Account?> getAccountById(String accountId) async {
try {
final doc = await _firestore.collection('accounts').doc(accountId).get();
if (doc.exists) {
return Account.fromMap(doc.data() as Map<String, dynamic>, doc.id);
}
return null;
} catch (e) {
throw Exception('Erreur lors de la récupération du compte: $e');
}
}
Future<Account?> 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<void> 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<Account?> watchAccount(String accountId) {
return _accountCollection.doc(accountId).snapshots().map((doc) {
if (doc.exists) {
return Account.fromMap(doc.data() as Map<String, dynamic>, doc.id);
}
return null;
});
}
Stream<Account?> 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<String, dynamic>, doc.id);
}
return null;
});
}
}

View File

@@ -9,7 +9,7 @@ class AccountService {
Stream<List<Account>> 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();
});