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 {
|
) async {
|
||||||
try {
|
try {
|
||||||
emit(GroupLoading());
|
emit(GroupLoading());
|
||||||
await _repository.createGroupWithMembers(
|
final groupId = await _repository.createGroupWithMembers(
|
||||||
group: event.group,
|
group: event.group,
|
||||||
members: event.members,
|
members: event.members,
|
||||||
);
|
);
|
||||||
emit(const GroupOperationSuccess('Groupe créé avec succès'));
|
emit(GroupCreated(groupId: groupId));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GroupError('Erreur lors de la création: $e'));
|
emit(GroupError('Erreur lors de la création: $e'));
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,6 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
|
|||||||
Emitter<GroupState> emit,
|
Emitter<GroupState> emit,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
// CORRECTION : Utiliser addMemberToGroup au lieu de addMember
|
|
||||||
await _repository.addMember(event.groupId, event.member);
|
await _repository.addMember(event.groupId, event.member);
|
||||||
emit(const GroupOperationSuccess('Membre ajouté'));
|
emit(const GroupOperationSuccess('Membre ajouté'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -124,7 +123,6 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
|
|||||||
Emitter<GroupState> emit,
|
Emitter<GroupState> emit,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
// CORRECTION : Utiliser removeMemberFromGroup au lieu de removeMember
|
|
||||||
await _repository.removeMember(event.groupId, event.userId);
|
await _repository.removeMember(event.groupId, event.userId);
|
||||||
emit(const GroupOperationSuccess('Membre supprimé'));
|
emit(const GroupOperationSuccess('Membre supprimé'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import '../../blocs/trip/trip_event.dart';
|
|||||||
import '../../blocs/trip/trip_state.dart';
|
import '../../blocs/trip/trip_state.dart';
|
||||||
import '../../blocs/group/group_bloc.dart';
|
import '../../blocs/group/group_bloc.dart';
|
||||||
import '../../blocs/group/group_event.dart';
|
import '../../blocs/group/group_event.dart';
|
||||||
import '../../blocs/group/group_state.dart';
|
|
||||||
import '../../blocs/account/account_bloc.dart';
|
import '../../blocs/account/account_bloc.dart';
|
||||||
import '../../blocs/account/account_event.dart';
|
import '../../blocs/account/account_event.dart';
|
||||||
import '../../models/account.dart';
|
import '../../models/account.dart';
|
||||||
@@ -111,15 +110,13 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocListener(
|
return BlocListener<TripBloc, TripState>(
|
||||||
listeners: [
|
|
||||||
// Listener pour TripBloc
|
|
||||||
BlocListener<TripBloc, TripState>(
|
|
||||||
listener: (context, tripState) {
|
listener: (context, tripState) {
|
||||||
if (tripState is TripCreated) {
|
if (tripState is TripCreated) {
|
||||||
// Stocker l'ID du trip et créer le groupe
|
// Stocker l'ID du trip et créer le groupe
|
||||||
_createdTripId = tripState.tripId;
|
_createdTripId = tripState.tripId;
|
||||||
_createGroupForTrip(tripState.tripId);
|
_createGroupForTrip(_createdTripId!);
|
||||||
|
_createAccountForTrip(_createdTripId!);
|
||||||
} else if (tripState is TripOperationSuccess) {
|
} else if (tripState is TripOperationSuccess) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -147,30 +144,6 @@ 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) {
|
builder: (context, userState) {
|
||||||
if (userState is! user_state.UserLoaded) {
|
if (userState is! user_state.UserLoaded) {
|
||||||
@@ -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>();
|
final accountBloc = context.read<AccountBloc>();
|
||||||
try {
|
try {
|
||||||
final userState = context.read<UserBloc>().state;
|
final userState = context.read<UserBloc>().state;
|
||||||
if (userState is! user_state.UserLoaded) return;
|
if (userState is! user_state.UserLoaded) return;
|
||||||
|
|
||||||
print('Creating account for trip $tripId and group $groupId');
|
|
||||||
|
|
||||||
final account = Account(
|
final account = Account(
|
||||||
id: '',
|
id: '',
|
||||||
tripId: tripId,
|
tripId: tripId,
|
||||||
groupId: groupId,
|
|
||||||
name: _titleController.text.trim(),
|
name: _titleController.text.trim(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -683,8 +653,6 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
members: accountsMembers,
|
members: accountsMembers,
|
||||||
));
|
));
|
||||||
|
|
||||||
print('++++++++++++++ Created account for trip $tripId and group $groupId ++++++++++++++');
|
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
|
|||||||
@@ -157,13 +157,15 @@ class _HomeContentState extends State<HomeContent> with AutomaticKeepAliveClient
|
|||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
final tripBloc = context.read<TripBloc>();
|
||||||
|
|
||||||
final result = await Navigator.push(
|
final result = await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) => const CreateTripContent()),
|
MaterialPageRoute(builder: (context) => const CreateTripContent()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result == true && mounted) {
|
if (result == true && mounted) {
|
||||||
context.read<TripBloc>().add(LoadTripsByUserId(userId: user.id));
|
tripBloc.add(LoadTripsByUserId(userId: user.id));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
|
|||||||
@@ -1,53 +1,61 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'group_member.dart';
|
import 'group_member.dart';
|
||||||
|
|
||||||
class Account {
|
class Account {
|
||||||
final String id;
|
final String id;
|
||||||
final String tripId;
|
final String tripId;
|
||||||
final String groupId;
|
|
||||||
final String name;
|
final String name;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
final List<GroupMember> members;
|
final List<GroupMember> members;
|
||||||
|
|
||||||
Account({
|
Account({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.tripId,
|
required this.tripId,
|
||||||
required this.groupId,
|
|
||||||
required this.name,
|
required this.name,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
List<GroupMember>? members,
|
List<GroupMember>? members,
|
||||||
}) : members = members ?? [];
|
}) : createdAt = createdAt ?? DateTime.now(),
|
||||||
|
updatedAt = updatedAt ?? DateTime.now(),
|
||||||
|
members = members ?? [];
|
||||||
|
|
||||||
|
factory Account.fromMap(Map<String, dynamic> map, String id) {
|
||||||
factory Account.fromMap(Map<String, dynamic> map) {
|
|
||||||
return Account(
|
return Account(
|
||||||
id: map['id'] as String,
|
id: id,
|
||||||
tripId: map['tripId'] as String,
|
tripId: map['tripId'] ?? '',
|
||||||
groupId: map['groupId'] as String,
|
name: map['name'] ?? '',
|
||||||
name: map['name'] as String,
|
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] ?? 0),
|
||||||
|
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] ?? 0),
|
||||||
members: [],
|
members: [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return {
|
||||||
'id': id,
|
|
||||||
'tripId': tripId,
|
'tripId': tripId,
|
||||||
'groupId': groupId,
|
|
||||||
'name': name,
|
'name': name,
|
||||||
'members': members.map((member) => member.toMap()).toList(),
|
'createdAt': createdAt.millisecondsSinceEpoch,
|
||||||
|
'updatedAt': updatedAt.millisecondsSinceEpoch,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
Account copyWith({
|
Account copyWith({
|
||||||
String? id,
|
String? id,
|
||||||
String? tripId,
|
String? tripId,
|
||||||
String? groupId,
|
|
||||||
String? name,
|
String? name,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
List<GroupMember>? members,
|
List<GroupMember>? members,
|
||||||
}) {
|
}) {
|
||||||
return Account(
|
return Account(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
tripId: tripId ?? this.tripId,
|
tripId: tripId ?? this.tripId,
|
||||||
groupId: groupId ?? this.groupId,
|
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
members: members ?? this.members,
|
members: members ?? this.members,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class Settlement extends Equatable {
|
|||||||
|
|
||||||
String get formattedAmount => '${amount.toStringAsFixed(2)} €';
|
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';
|
String get shortDescription => '$fromUserName → $toUserName';
|
||||||
|
|
||||||
@@ -125,6 +125,6 @@ class Settlement extends Equatable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Settlement(${shortDescription}: ${formattedAmount}, status: $status)';
|
return 'Settlement($shortDescription: $formattedAmount, status: $status)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,9 +54,8 @@ class AccountRepository {
|
|||||||
.get();
|
.get();
|
||||||
if (memberDoc.exists) {
|
if (memberDoc.exists) {
|
||||||
final accountData = accountDoc.data() as Map<String, dynamic>;
|
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);
|
final members = await getAccountMembers(accountId);
|
||||||
|
|
||||||
userAccounts.add(account.copyWith(members: members));
|
userAccounts.add(account.copyWith(members: members));
|
||||||
} else {
|
} else {
|
||||||
_errorService.logInfo('account_repository.dart', 'Utilisateur NON membre de $accountId');
|
_errorService.logInfo('account_repository.dart', 'Utilisateur NON membre de $accountId');
|
||||||
@@ -99,15 +98,44 @@ class AccountRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DocumentSnapshot> getAccountById(String accountId) async {
|
Future<Account?> getAccountById(String accountId) async {
|
||||||
return await _firestore.collection('accounts').doc(accountId).get();
|
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 {
|
Future<void> updateAccount(String accountId, Account account) async {
|
||||||
try {
|
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) {
|
} catch (e) {
|
||||||
_errorService.logError('account_repository.dart', 'Erreur lors de la mise à jour du compte: $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;
|
final docId = querySnapshot.docs.first.id;
|
||||||
|
|
||||||
|
// Supprimer tous les membres
|
||||||
final membersSnapshot = await _membersCollection(docId).get();
|
final membersSnapshot = await _membersCollection(docId).get();
|
||||||
for (var memberDoc in membersSnapshot.docs) {
|
for (var memberDoc in membersSnapshot.docs) {
|
||||||
await _membersCollection(docId).doc(memberDoc.id).delete();
|
await _membersCollection(docId).doc(memberDoc.id).delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Supprimer le compte
|
||||||
await _accountCollection.doc(docId).delete();
|
await _accountCollection.doc(docId).delete();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_errorService.logError('account_repository.dart', 'Erreur lors de la suppression du compte: $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(),
|
.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() {
|
Stream<List<Account>> getAccountsStream() {
|
||||||
return _firestore.collection('accounts').snapshots().map((snapshot) {
|
return _firestore.collection('accounts').snapshots().map((snapshot) {
|
||||||
return snapshot.docs.map((doc) {
|
return snapshot.docs.map((doc) {
|
||||||
return Account.fromMap(doc.data());
|
return Account.fromMap(doc.data(), doc.id);
|
||||||
}).toList();
|
}).toList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -52,8 +52,8 @@ class AccountService {
|
|||||||
.snapshots()
|
.snapshots()
|
||||||
.map((snapshot) {
|
.map((snapshot) {
|
||||||
return snapshot.docs.map((doc) {
|
return snapshot.docs.map((doc) {
|
||||||
final account = Account.fromMap(doc.data());
|
final account = Account.fromMap(doc.data(), doc.id);
|
||||||
_errorService.logError('Compte: ${account.name}, Membres: ${account.members.length}', StackTrace.current);
|
_errorService.logError('Compte: ${account.name}', StackTrace.current);
|
||||||
return account;
|
return account;
|
||||||
}).toList();
|
}).toList();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user