feat: Refactor account handling and improve group creation logic
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)';
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user