284 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| 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_form_actions.dart';
 | |
| import 'package:em2rp/views/widgets/inputs/option_selector_widget.dart';
 | |
| 
 | |
| class EventAddEditPage extends StatefulWidget {
 | |
|   final EventModel? event;
 | |
|   const EventAddEditPage({super.key, this.event});
 | |
| 
 | |
|   @override
 | |
|   State<EventAddEditPage> createState() => _EventAddEditPageState();
 | |
| }
 | |
| 
 | |
| class _EventAddEditPageState extends State<EventAddEditPage> {
 | |
|   final _formKey = GlobalKey<FormState>();
 | |
|   late EventFormController _controller;
 | |
| 
 | |
|   bool get isEditMode => widget.event != null;
 | |
| 
 | |
|   @override
 | |
|   void initState() {
 | |
|     super.initState();
 | |
|     _controller = EventFormController();
 | |
|     _controller.initialize(widget.event);
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void dispose() {
 | |
|     _controller.dispose();
 | |
|     super.dispose();
 | |
|   }
 | |
| 
 | |
|   Future<bool> _onWillPop() async {
 | |
|     if (!_controller.formChanged) return true;
 | |
|     if (!mounted) return true;
 | |
| 
 | |
|     final shouldLeave = await showDialog<bool>(
 | |
|       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<void> _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<void> _deleteEvent() async {
 | |
|     if (widget.event == null) return;
 | |
| 
 | |
|     final shouldDelete = await showDialog<bool>(
 | |
|       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();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @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(
 | |
|           appBar: AppBar(
 | |
|             title: Text(isEditMode ? 'Modifier un événement' : 'Créer un événement'),
 | |
|           ),
 | |
|           body: Center(
 | |
|             child: SingleChildScrollView(
 | |
|               child: (isMobile
 | |
|                   ? Padding(
 | |
|                       padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
 | |
|                       child: _buildFormContent(isMobile),
 | |
|                     )
 | |
|                   : Card(
 | |
|                       elevation: 6,
 | |
|                       margin: const EdgeInsets.all(24),
 | |
|                       shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
 | |
|                       child: Padding(
 | |
|                         padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 32),
 | |
|                         child: _buildFormContent(isMobile),
 | |
|                       ),
 | |
|                     )),
 | |
|             ),
 | |
|           ),
 | |
|         ),
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   Widget _buildFormContent(bool isMobile) {
 | |
|     return Consumer<EventFormController>(
 | |
|       builder: (context, controller, child) {
 | |
|         // Trouver le nom du type d'événement pour le passer au sélecteur d'options
 | |
|         final selectedEventTypeIndex = controller.selectedEventTypeId != null
 | |
|             ? controller.eventTypes.indexWhere((et) => et.id == controller.selectedEventTypeId)
 | |
|             : -1;
 | |
|         final selectedEventType = selectedEventTypeIndex != -1
 | |
|             ? controller.eventTypes[selectedEventTypeIndex]
 | |
|             : null;
 | |
|         final selectedEventTypeName = selectedEventType?.name;
 | |
| 
 | |
|         return Form(
 | |
|           key: _formKey,
 | |
|           child: Column(
 | |
|             mainAxisSize: MainAxisSize.min,
 | |
|             crossAxisAlignment: CrossAxisAlignment.stretch,
 | |
|             children: [
 | |
|               EventBasicInfoSection(
 | |
|                 nameController: controller.nameController,
 | |
|                 basePriceController: controller.basePriceController,
 | |
|                 eventTypes: controller.eventTypes,
 | |
|                 isLoadingEventTypes: controller.isLoadingEventTypes,
 | |
|                 selectedEventTypeId: controller.selectedEventTypeId,
 | |
|                 startDateTime: controller.startDateTime,
 | |
|                 endDateTime: controller.endDateTime,
 | |
|                 onEventTypeChanged: (typeId) => controller.onEventTypeChanged(typeId, context),
 | |
|                 onStartDateTimeChanged: controller.setStartDateTime,
 | |
|                 onEndDateTimeChanged: controller.setEndDateTime,
 | |
|                 onAnyFieldChanged: () {}, // Géré automatiquement par le contrôleur
 | |
|               ),
 | |
|               const SizedBox(height: 16),
 | |
|               OptionSelectorWidget(
 | |
|                 eventType: controller.selectedEventTypeId, // Utilise l'ID au lieu du nom
 | |
|                 selectedOptions: controller.selectedOptions,
 | |
|                 onChanged: controller.setSelectedOptions,
 | |
|                 onRemove: (optionId) {
 | |
|                   final newOptions = List<Map<String, dynamic>>.from(controller.selectedOptions);
 | |
|                   newOptions.removeWhere((o) => o['id'] == optionId);
 | |
|                   controller.setSelectedOptions(newOptions);
 | |
|                 },
 | |
|                 eventTypeRequired: controller.selectedEventTypeId == null,
 | |
|                 isMobile: isMobile,
 | |
|               ),
 | |
|               EventDetailsSection(
 | |
|                 descriptionController: controller.descriptionController,
 | |
|                 installationController: controller.installationController,
 | |
|                 disassemblyController: controller.disassemblyController,
 | |
|                 addressController: controller.addressController,
 | |
|                 isMobile: isMobile,
 | |
|                 onAnyFieldChanged: () {}, // Géré automatiquement par le contrôleur
 | |
|               ),
 | |
|               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: 16.0),
 | |
|                   child: Text(
 | |
|                     controller.error!,
 | |
|                     style: const TextStyle(color: Colors.red),
 | |
|                     textAlign: TextAlign.center,
 | |
|                   ),
 | |
|                 ),
 | |
|               if (controller.success != null)
 | |
|                 Padding(
 | |
|                   padding: const EdgeInsets.only(top: 16.0),
 | |
|                   child: Text(
 | |
|                     controller.success!,
 | |
|                     style: const TextStyle(color: Colors.green),
 | |
|                     textAlign: TextAlign.center,
 | |
|                   ),
 | |
|                 ),
 | |
|               EventFormActions(
 | |
|                 isLoading: controller.isLoading,
 | |
|                 isEditMode: isEditMode,
 | |
|                 onCancel: () async {
 | |
|                   final shouldLeave = await _onWillPop();
 | |
|                   if (shouldLeave && mounted) {
 | |
|                     Navigator.of(context).pop();
 | |
|                   }
 | |
|                 },
 | |
|                 onSubmit: _submit,
 | |
|                 onSetConfirmed: !isEditMode ? () {
 | |
|                 } : null,
 | |
|                 onDelete: isEditMode ? _deleteEvent : null, // Ajout du callback de suppression
 | |
|               ),
 | |
|             ],
 | |
|           ),
 | |
|         );
 | |
|       },
 | |
|     );
 | |
|   }
 | |
| }
 | 
