feat: ajout de la gestion de la préparation d'un événement avec page permettant de le gérer

This commit is contained in:
ElPoyo
2026-01-06 10:53:23 +01:00
parent fa1d6a4295
commit 25d395b41a
18 changed files with 2121 additions and 500 deletions

View File

@@ -7,6 +7,7 @@ import 'package:em2rp/providers/event_provider.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_details_navigation.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_details_header.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_status_button.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_preparation_buttons.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_details_info.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_details_description.dart';
import 'package:em2rp/views/widgets/calendar_widgets/event_details_components/event_details_documents.dart';
@@ -60,6 +61,8 @@ class EventDetails extends StatelessWidget {
onSelectEvent: onSelectEvent,
),
),
// Boutons de préparation et retour
EventPreparationButtons(event: event),
const SizedBox(height: 16),
Expanded(
child: SingleChildScrollView(

View File

@@ -98,8 +98,8 @@ class _EventDetailsHeaderState extends State<EventDetailsHeader> {
_buildStatusIcon(widget.event.status),
const SizedBox(width: 8),
IconButton(
icon: const Icon(Icons.calendar_today, color: AppColors.rouge),
tooltip: 'Exporter vers Google Calendar',
icon: const Icon(Icons.add_to_home_screen, color: AppColors.rouge),
tooltip: 'Ajouter a mon application de calendrier',
onPressed: _exportToCalendar,
),
if (Provider.of<LocalUserProvider>(context, listen: false)

View File

@@ -0,0 +1,160 @@
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:em2rp/models/event_model.dart';
import 'package:em2rp/views/event_preparation_page.dart';
import 'package:em2rp/utils/colors.dart';
/// Boutons de préparation et retour d'événement
class EventPreparationButtons extends StatefulWidget {
final EventModel event;
const EventPreparationButtons({
super.key,
required this.event,
});
@override
State<EventPreparationButtons> createState() => _EventPreparationButtonsState();
}
class _EventPreparationButtonsState extends State<EventPreparationButtons> {
@override
Widget build(BuildContext context) {
// Écouter les changements de l'événement en temps réel
return StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('events')
.doc(widget.event.id)
.snapshots(),
initialData: null,
builder: (context, snapshot) {
// Utiliser l'événement du stream si disponible, sinon l'événement initial
final EventModel currentEvent;
if (snapshot.hasData && snapshot.data != null && snapshot.data!.exists) {
currentEvent = EventModel.fromMap(
snapshot.data!.data() as Map<String, dynamic>,
snapshot.data!.id,
);
} else {
currentEvent = widget.event;
}
return _buildButtons(context, currentEvent);
},
);
}
Widget _buildButtons(BuildContext context, EventModel event) {
// Vérifier s'il y a du matériel assigné
final hasMaterial = event.assignedEquipment.isNotEmpty || event.assignedContainers.isNotEmpty;
if (!hasMaterial) {
return const SizedBox.shrink();
}
// Déterminer l'étape actuelle
final prep = event.preparationStatus ?? PreparationStatus.notStarted;
final loading = event.loadingStatus ?? LoadingStatus.notStarted;
final unloading = event.unloadingStatus ?? UnloadingStatus.notStarted;
final returnStatus = event.returnStatus ?? ReturnStatus.notStarted;
String buttonText;
IconData buttonIcon;
bool isCompleted = false;
if (prep != PreparationStatus.completed) {
buttonText = 'Préparation dépôt';
buttonIcon = Icons.inventory_2;
} else if (loading != LoadingStatus.completed) {
buttonText = 'Chargement aller';
buttonIcon = Icons.local_shipping;
} else if (unloading != UnloadingStatus.completed) {
buttonText = 'Chargement retour';
buttonIcon = Icons.unarchive;
} else if (returnStatus != ReturnStatus.completed) {
buttonText = 'Retour dépôt';
buttonIcon = Icons.assignment_return;
} else {
buttonText = 'Terminé';
buttonIcon = Icons.check_circle;
isCompleted = true;
}
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Bouton de l'étape actuelle
if (!isCompleted)
ElevatedButton.icon(
onPressed: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EventPreparationPage(
initialEvent: event,
),
),
);
// Si la validation a réussi, le StreamBuilder se rechargera automatiquement
if (result == true && context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Étape validée avec succès'),
backgroundColor: Colors.green,
),
);
}
},
icon: Icon(buttonIcon),
label: Text(
buttonText,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.bleuFonce,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
// Indicateur de completion
if (isCompleted)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.green.shade100,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green, width: 1),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(Icons.check_circle, color: Colors.green, size: 20),
SizedBox(width: 8),
Text(
'Toutes les étapes sont terminées',
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
],
),
);
}
}