import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/models/event_model.dart'; import 'package:em2rp/controllers/event_form_controller.dart'; import 'package:em2rp/views/widgets/event_form/event_basic_info_section.dart'; import 'package:em2rp/views/widgets/event_form/event_details_section.dart'; import 'package:em2rp/views/widgets/event_form/event_staff_and_documents_section.dart'; import 'package:em2rp/views/widgets/event_form/event_assigned_equipment_section.dart'; import 'package:em2rp/views/widgets/event_form/event_form_actions.dart'; import 'package:em2rp/views/widgets/inputs/option_selector_widget.dart'; class EventAddEditPage extends StatefulWidget { final EventModel? event; final DateTime? selectedDate; const EventAddEditPage({super.key, this.event, this.selectedDate}); @override State createState() => _EventAddEditPageState(); } class _EventAddEditPageState extends State { final _formKey = GlobalKey(); late EventFormController _controller; bool get isEditMode => widget.event != null; @override void initState() { super.initState(); _controller = EventFormController(); _controller.initialize( existingEvent: widget.event, selectedDate: widget.selectedDate, ); } @override void dispose() { _controller.dispose(); super.dispose(); } Future _onWillPop() async { if (!_controller.formChanged) return true; if (!mounted) return true; final shouldLeave = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Quitter la page ?'), content: const Text( 'Les modifications non enregistrées seront perdues. Voulez-vous vraiment quitter ?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('Annuler'), ), ElevatedButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('Quitter'), ), ], ), ); return shouldLeave ?? false; } Future _submit() async { if (!_formKey.currentState!.validate()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Veuillez remplir tous les champs obligatoires.'), backgroundColor: Colors.red, ), ); return; } final success = await _controller.submitForm(context, existingEvent: widget.event); if (success && mounted) { Navigator.of(context).pop(); } } Future _deleteEvent() async { if (widget.event == null) return; final shouldDelete = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Supprimer l\'événement'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Êtes-vous sûr de vouloir supprimer cet événement ?'), const SizedBox(height: 8), Text( 'Nom : ${widget.event!.name}', style: const TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 16), const Text( 'Cette action est irréversible.', style: TextStyle( color: Colors.red, fontWeight: FontWeight.bold, ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('Annuler'), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, ), onPressed: () => Navigator.of(context).pop(true), child: const Text('Supprimer'), ), ], ), ); if (shouldDelete == true) { final success = await _controller.deleteEvent(context, widget.event!.id); if (success && mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Événement supprimé avec succès'), backgroundColor: Colors.green, ), ); Navigator.of(context).pop(); } } } Widget _buildCard({ required String title, required IconData icon, required List children, }) { return Card( elevation: 0, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: Colors.grey.shade200, width: 1), ), child: Padding( padding: const EdgeInsets.all(24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFFD32F2F).withOpacity(0.1), // AppColors.rouge borderRadius: BorderRadius.circular(10), ), child: Icon(icon, color: const Color(0xFFD32F2F), size: 22), ), const SizedBox(width: 16), Expanded( child: Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ), ], ), const SizedBox(height: 24), ...children, ], ), ), ); } @override Widget build(BuildContext context) { final isMobile = MediaQuery.of(context).size.width < 600; return ChangeNotifierProvider.value( value: _controller, child: PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) async { if (didPop) return; final shouldPop = await _onWillPop(); if (shouldPop && mounted) { Navigator.of(context).pop(); } }, child: Scaffold( backgroundColor: Colors.grey.shade50, appBar: AppBar( title: Text( isEditMode ? 'Modifier un événement' : 'Créer un événement'), elevation: 0, ), body: SingleChildScrollView( child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 1200), child: Padding( padding: EdgeInsets.symmetric( horizontal: isMobile ? 16 : 32, vertical: 32), child: _buildFormContent(isMobile), ), ), ), ), ), ), ); } Widget _buildFormContent(bool isMobile) { return Consumer( builder: (context, controller, child) { return Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildCard( title: 'Informations générales', icon: Icons.event_note, children: [ EventBasicInfoSection( nameController: controller.nameController, basePriceController: controller.basePriceController, eventTypes: controller.eventTypes, isLoadingEventTypes: controller.isLoadingEventTypes, selectedEventTypeId: controller.selectedEventTypeId, startDateTime: controller.startDateTime, endDateTime: controller.endDateTime, selectedOptions: controller.selectedOptions, onEventTypeChanged: (typeId) => controller.onEventTypeChanged(typeId, context), onStartDateTimeChanged: controller.setStartDateTime, onEndDateTimeChanged: controller.setEndDateTime, onAnyFieldChanged: () {}, ), const SizedBox(height: 16), OptionSelectorWidget( eventType: controller.selectedEventTypeId, selectedOptions: controller.selectedOptions, onChanged: controller.setSelectedOptions, onRemove: (optionId) { final newOptions = List>.from( controller.selectedOptions); newOptions.removeWhere((o) => o['id'] == optionId); controller.setSelectedOptions(newOptions); }, eventTypeRequired: controller.selectedEventTypeId == null, isMobile: isMobile, ), ], ), const SizedBox(height: 24), // Section Matériel Assigné (gère sa propre carte pour inclure les boutons d'action dans le header) EventAssignedEquipmentSection( assignedEquipment: controller.assignedEquipment, assignedContainers: controller.assignedContainers, startDate: controller.startDateTime, endDate: controller.endDateTime, onChanged: controller.setAssignedEquipment, eventId: widget.event?.id, eventTypeId: controller.selectedEventTypeId, ), const SizedBox(height: 24), _buildCard( title: 'Détails & Logistique', icon: Icons.location_on_outlined, children: [ EventDetailsSection( descriptionController: controller.descriptionController, installationController: controller.installationController, disassemblyController: controller.disassemblyController, addressController: controller.addressController, jaugeController: controller.jaugeController, contactEmailController: controller.contactEmailController, contactPhoneController: controller.contactPhoneController, isMobile: isMobile, onAnyFieldChanged: () {}, // Géré automatiquement par le contrôleur onTravelCostSelected: (price) { controller.addTravelCostOption(price); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Frais de déplacement ajoutés : ${price.toStringAsFixed(2)} €'), backgroundColor: Colors.green, duration: const Duration(seconds: 3), ), ); }, ), ], ), const SizedBox(height: 24), _buildCard( title: 'Personnel & Documents', icon: Icons.group_outlined, children: [ EventStaffAndDocumentsSection( allUsers: controller.allUsers, selectedUserIds: controller.selectedUserIds, onUserSelectionChanged: controller.setSelectedUserIds, isLoadingUsers: controller.isLoadingUsers, uploadedFiles: controller.uploadedFiles, onFilesChanged: controller.setUploadedFiles, isLoading: controller.isLoading, error: controller.error, success: controller.success, isMobile: isMobile, onPickAndUploadFiles: controller.pickAndUploadFiles, ), ], ), if (controller.error != null) Padding( padding: const EdgeInsets.only(top: 24.0), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.red.shade200) ), child: Row( children: [ Icon(Icons.error_outline, color: Colors.red.shade700), const SizedBox(width: 12), Expanded( child: Text( controller.error!, style: TextStyle(color: Colors.red.shade700), ), ), ], ), ), ), if (controller.success != null) Padding( padding: const EdgeInsets.only(top: 24.0), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.green.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.green.shade200) ), child: Row( children: [ Icon(Icons.check_circle_outline, color: Colors.green.shade700), const SizedBox(width: 12), Expanded( child: Text( controller.success!, style: TextStyle(color: Colors.green.shade700), ), ), ], ), ), ), const SizedBox(height: 24), EventFormActions( isLoading: controller.isLoading, isEditMode: isEditMode, onCancel: () async { final shouldLeave = await _onWillPop(); if (shouldLeave && mounted) { Navigator.of(context).pop(); } }, onSubmit: _submit, onSetConfirmed: !isEditMode ? () async { final success = await controller.submitAsConfirmed(context); if (success && context.mounted) { Navigator.of(context).pop(); } } : null, onDelete: isEditMode ? _deleteEvent : null, ), const SizedBox(height: 48), // Padding bottom for scrolling ], ), ); }, ); } }