import 'package:flutter/material.dart'; import 'package:em2rp/models/event_model.dart'; import 'package:em2rp/utils/colors.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/providers/local_user_provider.dart'; import 'package:em2rp/providers/event_provider.dart'; import 'package:latlong2/latlong.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:path/path.dart' as p; class EventDetails extends StatelessWidget { final EventModel event; final DateTime? selectedDate; final List events; final void Function(EventModel, DateTime) onSelectEvent; const EventDetails({ super.key, required this.event, required this.selectedDate, required this.events, required this.onSelectEvent, }); @override Widget build(BuildContext context) { final dateFormat = DateFormat('dd/MM/yyyy HH:mm'); final currencyFormat = NumberFormat.currency(locale: 'fr_FR', symbol: '€'); final fullDateFormat = DateFormat('EEEE d MMMM y', 'fr_FR'); // Trie les événements par date de début final sortedEvents = List.from(events) ..sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); final currentIndex = sortedEvents.indexWhere((e) => e.id == event.id); final localUserProvider = Provider.of(context); final isAdmin = localUserProvider.hasPermission('view_all_users'); return Card( margin: const EdgeInsets.all(16), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( onPressed: currentIndex > 0 ? () { final prevEvent = sortedEvents[currentIndex - 1]; onSelectEvent(prevEvent, prevEvent.startDateTime); } : null, icon: const Icon(Icons.arrow_back), color: AppColors.rouge, ), if (selectedDate != null) Expanded( child: Center( child: Text( fullDateFormat.format(selectedDate!), style: Theme.of(context).textTheme.titleLarge?.copyWith( color: AppColors.rouge, fontWeight: FontWeight.bold, ), ), ), ), IconButton( onPressed: currentIndex < sortedEvents.length - 1 ? () { final nextEvent = sortedEvents[currentIndex + 1]; onSelectEvent(nextEvent, nextEvent.startDateTime); } : null, icon: const Icon(Icons.arrow_forward), color: AppColors.rouge, ), ], ), const SizedBox(height: 16), Text( event.name, style: Theme.of(context).textTheme.headlineMedium?.copyWith( color: AppColors.noir, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), _buildInfoRow( context, Icons.calendar_today, 'Date de début', dateFormat.format(event.startDateTime), ), _buildInfoRow( context, Icons.calendar_today, 'Date de fin', dateFormat.format(event.endDateTime), ), _buildInfoRow( context, Icons.euro, 'Prix', currencyFormat.format(event.price), ), _buildInfoRow( context, Icons.build, 'Temps d\'installation', '${event.installationTime} heures', ), _buildInfoRow( context, Icons.construction, 'Temps de démontage', '${event.disassemblyTime} heures', ), const SizedBox(height: 16), Text( 'Description', style: Theme.of(context).textTheme.titleLarge?.copyWith( color: AppColors.noir, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( event.description, style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox(height: 16), Text( 'Adresse', style: Theme.of(context).textTheme.titleLarge?.copyWith( color: AppColors.noir, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( event.address, style: Theme.of(context).textTheme.bodyLarge, ), if (event.latitude != 0.0 || event.longitude != 0.0) ...[ const SizedBox(height: 4), Text( '${event.latitude}° N, ${event.longitude}° E', style: Theme.of(context).textTheme.bodySmall, ), ], if (event.documents.isNotEmpty) ...[ const SizedBox(height: 16), Text('Documents', style: Theme.of(context).textTheme.titleLarge?.copyWith( color: AppColors.noir, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: event.documents.map((doc) { final fileName = doc['name'] ?? ''; final url = doc['url'] ?? ''; final ext = p.extension(fileName).toLowerCase(); IconData icon; if ([".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"] .contains(ext)) { icon = Icons.image; } else if (ext == ".pdf") { icon = Icons.picture_as_pdf; } else if ([ ".txt", ".md", ".csv", ".json", ".xml", ".docx", ".doc", ".xls", ".xlsx", ".ppt", ".pptx" ].contains(ext)) { icon = Icons.description; } else { icon = Icons.attach_file; } return ListTile( leading: Icon(icon, color: Colors.blueGrey), title: Text(fileName, overflow: TextOverflow.ellipsis), trailing: IconButton( icon: const Icon(Icons.download), onPressed: () async { if (await canLaunchUrl(Uri.parse(url))) { await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); } }, ), onTap: () async { if (await canLaunchUrl(Uri.parse(url))) { await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); } }, contentPadding: EdgeInsets.zero, dense: true, ); }).toList(), ), ], ], ), ), ); } Widget _buildInfoRow( BuildContext context, IconData icon, String label, String value, ) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Icon(icon, color: AppColors.rouge), const SizedBox(width: 8), Text( '$label : ', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: AppColors.noir, fontWeight: FontWeight.bold, ), ), Text( value, style: Theme.of(context).textTheme.titleMedium, ), ], ), ); } } class EventAddDialog extends StatefulWidget { const EventAddDialog({super.key}); @override State createState() => _EventAddDialogState(); } class _EventAddDialogState extends State { final _formKey = GlobalKey(); final TextEditingController _nameController = TextEditingController(); final TextEditingController _descriptionController = TextEditingController(); final TextEditingController _priceController = TextEditingController(); final TextEditingController _installationController = TextEditingController(); final TextEditingController _disassemblyController = TextEditingController(); final TextEditingController _latitudeController = TextEditingController(); final TextEditingController _longitudeController = TextEditingController(); final TextEditingController _addressController = TextEditingController(); DateTime? _startDateTime; DateTime? _endDateTime; bool _isLoading = false; String? _error; String? _success; @override void dispose() { _nameController.dispose(); _descriptionController.dispose(); _priceController.dispose(); _installationController.dispose(); _disassemblyController.dispose(); _latitudeController.dispose(); _longitudeController.dispose(); _addressController.dispose(); super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate() || _startDateTime == null || _endDateTime == null) return; setState(() { _isLoading = true; _error = null; _success = null; }); try { final eventProvider = Provider.of(context, listen: false); final newEvent = EventModel( id: '', name: _nameController.text.trim(), description: _descriptionController.text.trim(), startDateTime: _startDateTime!, endDateTime: _endDateTime!, price: double.tryParse(_priceController.text) ?? 0.0, installationTime: int.tryParse(_installationController.text) ?? 0, disassemblyTime: int.tryParse(_disassemblyController.text) ?? 0, eventTypeId: '', // à adapter si tu veux gérer les types customerId: '', // à adapter si tu veux gérer les clients address: _addressController.text.trim(), latitude: double.tryParse(_latitudeController.text) ?? 0.0, longitude: double.tryParse(_longitudeController.text) ?? 0.0, workforce: [], documents: [], ); await eventProvider.addEvent(newEvent); setState(() { _success = "Événement créé avec succès !"; }); Navigator.of(context).pop(); } catch (e) { setState(() { _error = "Erreur lors de la création : $e"; }); } finally { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Créer un événement'), content: SingleChildScrollView( child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextFormField( controller: _nameController, decoration: const InputDecoration(labelText: 'Nom'), validator: (v) => v == null || v.isEmpty ? 'Champ requis' : null, ), TextFormField( controller: _descriptionController, decoration: const InputDecoration(labelText: 'Description'), maxLines: 2, ), TextFormField( controller: _priceController, decoration: const InputDecoration(labelText: 'Prix (€)'), keyboardType: TextInputType.number, ), TextFormField( controller: _installationController, decoration: const InputDecoration(labelText: 'Installation (h)'), keyboardType: TextInputType.number, ), TextFormField( controller: _disassemblyController, decoration: const InputDecoration(labelText: 'Démontage (h)'), keyboardType: TextInputType.number, ), TextFormField( controller: _latitudeController, decoration: const InputDecoration(labelText: 'Latitude'), keyboardType: TextInputType.number, ), TextFormField( controller: _longitudeController, decoration: const InputDecoration(labelText: 'Longitude'), keyboardType: TextInputType.number, ), TextFormField( controller: _addressController, decoration: const InputDecoration(labelText: 'Adresse'), ), const SizedBox(height: 8), Row( children: [ Expanded( child: OutlinedButton( onPressed: () async { final picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), ); if (picked != null) { final time = await showTimePicker( context: context, initialTime: TimeOfDay.now(), ); if (time != null) { setState(() { _startDateTime = DateTime( picked.year, picked.month, picked.day, time.hour, time.minute, ); }); } } }, child: Text(_startDateTime == null ? 'Début' : DateFormat('dd/MM/yyyy HH:mm') .format(_startDateTime!)), ), ), const SizedBox(width: 8), Expanded( child: OutlinedButton( onPressed: () async { final picked = await showDatePicker( context: context, initialDate: _startDateTime ?? DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), ); if (picked != null) { final time = await showTimePicker( context: context, initialTime: TimeOfDay.now(), ); if (time != null) { setState(() { _endDateTime = DateTime( picked.year, picked.month, picked.day, time.hour, time.minute, ); }); } } }, child: Text(_endDateTime == null ? 'Fin' : DateFormat('dd/MM/yyyy HH:mm') .format(_endDateTime!)), ), ), ], ), if (_error != null) Padding( padding: const EdgeInsets.only(top: 8.0), child: Text(_error!, style: const TextStyle(color: Colors.red)), ), if (_success != null) Padding( padding: const EdgeInsets.only(top: 8.0), child: Text(_success!, style: const TextStyle(color: Colors.green)), ), ], ), ), ), actions: [ TextButton( onPressed: _isLoading ? null : () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ElevatedButton( onPressed: _isLoading ? null : _submit, child: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Text('Créer'), ), ], ); } }