Equipe sur event details OK

Modif evenement OK
This commit is contained in:
2025-06-03 19:59:40 +02:00
parent acab16e101
commit 57c59c911a
6 changed files with 299 additions and 111 deletions

View File

@ -9,6 +9,10 @@ import 'package:latlong2/latlong.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:path/path.dart' as p;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:em2rp/views/widgets/user_management/user_card.dart';
import 'package:em2rp/models/user_model.dart';
import 'package:em2rp/views/widgets/user_management/user_multi_select_widget.dart';
import 'package:em2rp/views/event_add_page.dart';
class EventDetails extends StatelessWidget {
final EventModel event;
@ -93,6 +97,20 @@ class EventDetails extends StatelessWidget {
),
const SizedBox(width: 12),
_buildStatusIcon(event.status),
const SizedBox(width: 8),
if (Provider.of<LocalUserProvider>(context, listen: false)
.hasPermission('edit_event'))
IconButton(
icon: const Icon(Icons.edit, color: AppColors.rouge),
tooltip: 'Modifier',
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EventAddEditPage(event: event),
),
);
},
),
],
),
if (Provider.of<LocalUserProvider>(context, listen: false)
@ -337,6 +355,9 @@ class EventDetails extends StatelessWidget {
);
}).toList(),
),
// --- EQUIPE SECTION ---
const SizedBox(height: 16),
EquipeSection(workforce: event.workforce),
],
],
),
@ -773,3 +794,80 @@ class _FirestoreStatusButtonState extends State<_FirestoreStatusButton> {
);
}
}
class EquipeSection extends StatelessWidget {
final List workforce;
const EquipeSection({super.key, required this.workforce});
@override
Widget build(BuildContext context) {
if (workforce.isEmpty) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Equipe',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.black,
fontWeight: FontWeight.bold,
)),
const SizedBox(height: 8),
Text('Aucun membre assigné.',
style: Theme.of(context).textTheme.bodyMedium),
],
);
}
return FutureBuilder<List<UserModel>>(
future: _fetchUsers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Center(child: CircularProgressIndicator()),
);
}
if (snapshot.hasError) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text('Erreur lors du chargement de l\'équipe',
style: TextStyle(color: Colors.red)),
);
}
final users = snapshot.data ?? [];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Equipe',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.black,
fontWeight: FontWeight.bold,
)),
const SizedBox(height: 8),
if (users.isEmpty)
Text('Aucun membre assigné.',
style: Theme.of(context).textTheme.bodyMedium),
if (users.isNotEmpty)
UserChipsList(
users: users,
showRemove: false,
),
],
);
},
);
}
Future<List<UserModel>> _fetchUsers() async {
final firestore = FirebaseFirestore.instance;
List<UserModel> users = [];
for (final ref in workforce) {
try {
final doc = await firestore.doc(ref.path).get();
if (doc.exists) {
users.add(
UserModel.fromMap(doc.data() as Map<String, dynamic>, doc.id));
}
} catch (_) {}
}
return users;
}
}

View File

@ -70,26 +70,15 @@ class _UserMultiSelectState extends State<_UserMultiSelect> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
spacing: 12,
runSpacing: 12,
children: selectedUsers
.map((user) => Chip(
avatar: ProfilePictureWidget(userId: user.uid, radius: 28),
label: Text('${user.firstName} ${user.lastName}',
style: const TextStyle(fontSize: 16)),
labelPadding: const EdgeInsets.symmetric(horizontal: 8),
deleteIcon: const Icon(Icons.close, size: 20),
onDeleted: () {
final newList = List<String>.from(widget.selectedUserIds)
..remove(user.uid);
widget.onChanged(newList);
},
backgroundColor: Colors.grey[200],
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
))
.toList(),
UserChipsList(
users: selectedUsers,
selectedUserIds: widget.selectedUserIds,
showRemove: true,
onRemove: (uid) {
final newList = List<String>.from(widget.selectedUserIds)
..remove(uid);
widget.onChanged(newList);
},
),
const SizedBox(height: 16),
ElevatedButton.icon(
@ -188,3 +177,43 @@ class _UserPickerDialogState extends State<_UserPickerDialog> {
);
}
}
class UserChipsList extends StatelessWidget {
final List<UserModel> users;
final List<String> selectedUserIds;
final ValueChanged<String>? onRemove;
final bool showRemove;
final double avatarRadius;
const UserChipsList({
super.key,
required this.users,
this.selectedUserIds = const [],
this.onRemove,
this.showRemove = false,
this.avatarRadius = 28,
});
@override
Widget build(BuildContext context) {
return Wrap(
spacing: 12,
runSpacing: 12,
children: users
.map((user) => Chip(
avatar: ProfilePictureWidget(
userId: user.uid, radius: avatarRadius),
label: Text('${user.firstName} ${user.lastName}',
style: const TextStyle(fontSize: 16)),
labelPadding: const EdgeInsets.symmetric(horizontal: 8),
deleteIcon:
showRemove ? const Icon(Icons.close, size: 20) : null,
onDeleted: showRemove && onRemove != null
? () => onRemove!(user.uid)
: null,
backgroundColor: Colors.grey[200],
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
))
.toList(),
);
}
}