feat: Enhance group and trip management with group creation and account linking
NOT FUNCTIONNAL
This commit is contained in:
@@ -79,10 +79,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: [],
|
members: [],
|
||||||
);
|
);
|
||||||
|
emit(GroupCreated(groupId: groupId));
|
||||||
emit(const GroupOperationSuccess('Groupe créé avec succès'));
|
emit(const GroupOperationSuccess('Groupe créé avec succès'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(GroupError('Erreur lors de la création: $e'));
|
emit(GroupError('Erreur lors de la création: $e'));
|
||||||
|
|||||||
@@ -30,6 +30,18 @@ class GroupLoaded extends GroupState {
|
|||||||
const GroupLoaded(this.groups);
|
const GroupLoaded(this.groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GroupCreated extends GroupState {
|
||||||
|
final String groupId;
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const GroupCreated({
|
||||||
|
required this.groupId,
|
||||||
|
this.message = 'Groupe créé avec succès',
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [groupId, message];
|
||||||
|
}
|
||||||
|
|
||||||
// Succès d'une opération
|
// Succès d'une opération
|
||||||
class GroupOperationSuccess extends GroupState {
|
class GroupOperationSuccess extends GroupState {
|
||||||
final String message;
|
final String message;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class TripLoaded extends TripState {
|
|||||||
List<Object?> get props => [trips];
|
List<Object?> get props => [trips];
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOUVEAU : État pour indiquer qu'un voyage a été créé avec succès
|
|
||||||
class TripCreated extends TripState {
|
class TripCreated extends TripState {
|
||||||
final String tripId;
|
final String tripId;
|
||||||
final String message;
|
final String message;
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ 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_event.dart';
|
||||||
|
import '../../models/account.dart';
|
||||||
import '../../models/group.dart';
|
import '../../models/group.dart';
|
||||||
import '../../models/group_member.dart';
|
import '../../models/group_member.dart';
|
||||||
import '../../services/user_service.dart';
|
import '../../services/user_service.dart';
|
||||||
@@ -38,6 +42,7 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
DateTime? _startDate;
|
DateTime? _startDate;
|
||||||
DateTime? _endDate;
|
DateTime? _endDate;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
String? _createdTripId;
|
||||||
|
|
||||||
final List<String> _participants = [];
|
final List<String> _participants = [];
|
||||||
final _participantController = TextEditingController();
|
final _participantController = TextEditingController();
|
||||||
@@ -106,38 +111,66 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocListener<TripBloc, TripState>(
|
return MultiBlocListener(
|
||||||
listener: (context, tripState) {
|
listeners: [
|
||||||
// Écouter l'état TripCreated pour récupérer l'ID du voyage
|
// Listener pour TripBloc
|
||||||
if (tripState is TripCreated) {
|
BlocListener<TripBloc, TripState>(
|
||||||
_createGroupForTrip(tripState.tripId);
|
listener: (context, tripState) {
|
||||||
} else if (tripState is TripOperationSuccess) {
|
if (tripState is TripCreated) {
|
||||||
if (mounted) {
|
// Stocker l'ID du trip et créer le groupe
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_createdTripId = tripState.tripId;
|
||||||
SnackBar(
|
_createGroupForTrip(tripState.tripId);
|
||||||
content: Text(tripState.message),
|
} else if (tripState is TripOperationSuccess) {
|
||||||
backgroundColor: Colors.green,
|
if (mounted) {
|
||||||
),
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
);
|
SnackBar(
|
||||||
Navigator.pop(context);
|
content: Text(tripState.message),
|
||||||
if (isEditing) {
|
backgroundColor: Colors.green,
|
||||||
Navigator.pop(context); // Retour supplémentaire en mode édition
|
),
|
||||||
|
);
|
||||||
|
Navigator.pop(context);
|
||||||
|
if (isEditing) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tripState is TripError) {
|
||||||
|
if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(tripState.message),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
} else if (tripState is TripError) {
|
),
|
||||||
if (mounted) {
|
// Nouveau listener pour GroupBloc
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
BlocListener<GroupBloc, GroupState>(
|
||||||
SnackBar(
|
listener: (context, groupState) {
|
||||||
content: Text(tripState.message),
|
if (groupState is GroupCreated && _createdTripId != null) {
|
||||||
backgroundColor: Colors.red,
|
// Le groupe a été créé, maintenant créer le compte
|
||||||
),
|
print('++++++++++++++ Creating account for trip ${_createdTripId!} and group ${groupState.groupId} ++++++++++++++');
|
||||||
);
|
_createAccountForTrip(_createdTripId!, groupState.groupId);
|
||||||
setState(() {
|
} else if (groupState is GroupError) {
|
||||||
_isLoading = false;
|
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) {
|
||||||
@@ -506,6 +539,7 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
user_state.UserModel currentUser,
|
user_state.UserModel currentUser,
|
||||||
List<Map<String, String>> participantsData,
|
List<Map<String, String>> participantsData,
|
||||||
) async {
|
) async {
|
||||||
|
final groupBloc = context.read<GroupBloc>();
|
||||||
try {
|
try {
|
||||||
final group = await _groupRepository.getGroupByTripId(tripId);
|
final group = await _groupRepository.getGroupByTripId(tripId);
|
||||||
|
|
||||||
@@ -517,20 +551,7 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final newMembers = <GroupMember>[
|
final newMembers = await _createMembers();
|
||||||
GroupMember(
|
|
||||||
userId: currentUser.id,
|
|
||||||
firstName: currentUser.prenom,
|
|
||||||
pseudo: currentUser.prenom,
|
|
||||||
role: 'admin',
|
|
||||||
),
|
|
||||||
...participantsData.map((p) => GroupMember(
|
|
||||||
userId: p['id'] as String,
|
|
||||||
firstName: p['firstName'] as String,
|
|
||||||
pseudo: p['firstName'] as String,
|
|
||||||
role: 'member',
|
|
||||||
)),
|
|
||||||
];
|
|
||||||
|
|
||||||
final currentMembers = await _groupRepository.getGroupMembers(group.id);
|
final currentMembers = await _groupRepository.getGroupMembers(group.id);
|
||||||
final currentMemberIds = currentMembers.map((m) => m.userId).toSet();
|
final currentMemberIds = currentMembers.map((m) => m.userId).toSet();
|
||||||
@@ -543,11 +564,15 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (final member in membersToAdd) {
|
for (final member in membersToAdd) {
|
||||||
context.read<GroupBloc>().add(AddMemberToGroup(group.id, member));
|
if (mounted) {
|
||||||
|
groupBloc.add(AddMemberToGroup(group.id, member));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final member in membersToRemove) {
|
for (final member in membersToRemove) {
|
||||||
context.read<GroupBloc>().add(RemoveMemberFromGroup(group.id, member.userId));
|
if (mounted) {
|
||||||
|
groupBloc.add(RemoveMemberFromGroup(group.id, member.userId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_errorService.logError(
|
_errorService.logError(
|
||||||
@@ -557,39 +582,53 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOUVELLE MÉTHODE : Créer le groupe après la création du voyage
|
Future<List<GroupMember>> _createMembers() async {
|
||||||
|
final userState = context.read<UserBloc>().state;
|
||||||
|
if (userState is! user_state.UserLoaded) return [];
|
||||||
|
|
||||||
|
final currentUser = userState.user;
|
||||||
|
final participantsData = await _getParticipantsData(_participants);
|
||||||
|
|
||||||
|
final groupMembers = <GroupMember>[
|
||||||
|
GroupMember(
|
||||||
|
userId: currentUser.id,
|
||||||
|
firstName: currentUser.prenom,
|
||||||
|
pseudo: currentUser.prenom,
|
||||||
|
role: 'admin',
|
||||||
|
),
|
||||||
|
...participantsData.map((p) => GroupMember(
|
||||||
|
userId: p['id'] as String,
|
||||||
|
firstName: p['firstName'] as String,
|
||||||
|
pseudo: p['firstName'] as String,
|
||||||
|
role: 'member',
|
||||||
|
)),
|
||||||
|
];
|
||||||
|
return groupMembers;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _createGroupForTrip(String tripId) async {
|
Future<void> _createGroupForTrip(String tripId) async {
|
||||||
|
final groupBloc = context.read<GroupBloc>();
|
||||||
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;
|
||||||
|
|
||||||
final currentUser = userState.user;
|
final currentUser = userState.user;
|
||||||
final participantsData = await _getParticipantsData(_participants);
|
|
||||||
|
|
||||||
// Créer le groupe avec le tripId récupéré
|
// Créer le groupe avec le tripId récupéré
|
||||||
final group = Group(
|
final group = Group(
|
||||||
id: '', // Sera généré par Firestore
|
id: '', // Sera généré par Firestore
|
||||||
name: _titleController.text.trim(),
|
name: _titleController.text.trim(),
|
||||||
tripId: tripId, // ✅ ID du voyage récupéré
|
tripId: tripId,
|
||||||
createdBy: currentUser.id,
|
createdBy: currentUser.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
final groupMembers = <GroupMember>[
|
final groupMembers = await _createMembers();
|
||||||
GroupMember(
|
|
||||||
userId: currentUser.id,
|
|
||||||
firstName: currentUser.prenom,
|
|
||||||
pseudo: currentUser.prenom,
|
|
||||||
role: 'admin',
|
|
||||||
),
|
|
||||||
...participantsData.map((p) => GroupMember(
|
|
||||||
userId: p['id'] as String,
|
|
||||||
firstName: p['firstName'] as String,
|
|
||||||
pseudo: p['firstName'] as String,
|
|
||||||
role: 'member',
|
|
||||||
)),
|
|
||||||
];
|
|
||||||
|
|
||||||
context.read<GroupBloc>().add(CreateGroupWithMembers(
|
if (groupMembers.isEmpty) {
|
||||||
|
throw Exception('Erreur lors de la création des membres du groupe');
|
||||||
|
}
|
||||||
|
|
||||||
|
groupBloc.add(CreateGroupWithMembers(
|
||||||
group: group,
|
group: group,
|
||||||
members: groupMembers,
|
members: groupMembers,
|
||||||
));
|
));
|
||||||
@@ -622,6 +661,60 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _createAccountForTrip(String tripId, String groupId) 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(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final accountsMembers = await _createMembers();
|
||||||
|
|
||||||
|
accountBloc.add(CreateAccountWithMembers(
|
||||||
|
account: account,
|
||||||
|
members: accountsMembers,
|
||||||
|
));
|
||||||
|
|
||||||
|
print('++++++++++++++ Created account for trip $tripId and group $groupId ++++++++++++++');
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Compte créé avec succès !'),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
_errorService.logError(
|
||||||
|
'create_trip_content.dart',
|
||||||
|
'Erreur lors de la création du compte: $e',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _saveTrip(user_state.UserModel currentUser) async {
|
Future<void> _saveTrip(user_state.UserModel currentUser) async {
|
||||||
if (!_formKey.currentState!.validate()) {
|
if (!_formKey.currentState!.validate()) {
|
||||||
return;
|
return;
|
||||||
@@ -640,6 +733,8 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final tripBloc = context.read<TripBloc>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final participantsData = await _getParticipantsData(_participants);
|
final participantsData = await _getParticipantsData(_participants);
|
||||||
List<String> participantIds = participantsData.map((p) => p['id'] as String).toList();
|
List<String> participantIds = participantsData.map((p) => p['id'] as String).toList();
|
||||||
@@ -664,16 +759,17 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
|
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
// Mode mise à jour
|
// Mode mise à jour
|
||||||
context.read<TripBloc>().add(TripUpdateRequested(trip: trip));
|
tripBloc.add(TripUpdateRequested(trip: trip));
|
||||||
|
|
||||||
await _updateGroupMembers(
|
await _updateGroupMembers(
|
||||||
widget.tripToEdit!.id!,
|
widget.tripToEdit!.id!,
|
||||||
currentUser,
|
currentUser,
|
||||||
participantsData,
|
participantsData,
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Mode création - Le groupe sera créé dans le listener TripCreated
|
// Mode création - Le groupe sera créé dans le listener TripCreated
|
||||||
context.read<TripBloc>().add(TripCreateRequested(trip: trip));
|
tripBloc.add(TripCreateRequested(trip: trip));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
|||||||
Reference in New Issue
Block a user