diff --git a/em2rp/.firebase/hosting.YnVpbGRcd2Vi.cache b/em2rp/.firebase/hosting.YnVpbGRcd2Vi.cache index fac4c7e..212dfcd 100644 --- a/em2rp/.firebase/hosting.YnVpbGRcd2Vi.cache +++ b/em2rp/.firebase/hosting.YnVpbGRcd2Vi.cache @@ -32,16 +32,16 @@ assets/assets/images/tshirt-incrust.webp,1737393735487,af7cb34adfca19c0b41c8eb63 assets/assets/icons/truss.svg,1761734811263,8ddfbbb4f96de5614348eb23fa55f61b2eb1edb064719a8bbd791c35883ec4cc assets/assets/icons/tape.svg,1761734809221,631183f0ff972aa4dc3f9f51dc7abd41a607df749d1f9a44fa7e77202d95ccde assets/assets/icons/flight-case.svg,1761734822495,0cef47fdf5d7efdd110763c32f792ef9735df35c4f42ae7d02d5fbda40e6148d -version.json,1768522475061,bddd1ea3e020d4aacf09b657c819bf5f36dc702aec076e506cb492d21cd8f52a -index.html,1768522480171,4e8c00552c71ef134bead8bc03706952e7a415d70fca602a3839dc02a3f7ae10 -flutter_service_worker.js,1768522568665,eba5c918ba4c29ed004c54e9bd663630cb2c583c3c71f06a8f2020b5752e7b01 -assets/FontManifest.json,1768522564284,e38b95988f5d060cf9b7ce97cb5ac9236d6f4cc04a11d69567df97b2b4cbc5e5 -flutter_bootstrap.js,1768522480160,97c0e7a0a2dc5def7e6753ab86c08de3efaae84ac9f0203e29554f4274511bb2 -assets/AssetManifest.json,1768522564284,1e1501af5844823ef215cf650f4cef4002c0389d88770225ac07576d57dc1067 -assets/AssetManifest.bin.json,1768522564284,f446eb3de964f3a6f9e76fcc98d79a81b0429e076c9c7bf30cf8edd0263a0b0a -assets/AssetManifest.bin,1768522564284,72bbccb69d9a02d3885df0c5e58ebfed29e25a4919e10bf195b59542f4709ca3 -assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1768522567845,d41473de1f7708a0702d7f19327693486512db442f6ab0cf7774e6d6576f9fcb -assets/shaders/ink_sparkle.frag,1768522564576,591c7517d5cb43eb91ea451e0d3f9f585cbf8298cf6c46a9144b77cb0775a406 -assets/fonts/MaterialIcons-Regular.otf,1768522567854,33efc485968dd28630ace587c22d6df359c195821b1114aaa85383e4d5394eac -assets/NOTICES,1768522564286,fc20c3c3c998057eb7e58ad2e009c7268bf748bfde685e95130431f4c54bd51c -main.dart.js,1768522561626,c106504190e4bf61c5a50eb6a4826ea8cddccd2310ffa359df51f047bf891acd +version.json,1768586208886,5a25871ae727f23c4b7258c34108085b8711aa94f6fcab512e0c3ca00a429a64 +index.html,1768586225248,4e8c00552c71ef134bead8bc03706952e7a415d70fca602a3839dc02a3f7ae10 +flutter_service_worker.js,1768586307073,4ea31c373e15f13c2916a12d9d799905af2a79ff7ed0bcceb4334707910c7721 +flutter_bootstrap.js,1768586225225,e95b1b0bd493a475c8eed0e630e413d898f2ceff11cd9b24c6c564bbc2c5f5e9 +assets/FontManifest.json,1768586302952,e38b95988f5d060cf9b7ce97cb5ac9236d6f4cc04a11d69567df97b2b4cbc5e5 +assets/AssetManifest.json,1768586302952,1e1501af5844823ef215cf650f4cef4002c0389d88770225ac07576d57dc1067 +assets/AssetManifest.bin.json,1768586302952,f446eb3de964f3a6f9e76fcc98d79a81b0429e076c9c7bf30cf8edd0263a0b0a +assets/AssetManifest.bin,1768586302952,72bbccb69d9a02d3885df0c5e58ebfed29e25a4919e10bf195b59542f4709ca3 +assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1768586306083,d41473de1f7708a0702d7f19327693486512db442f6ab0cf7774e6d6576f9fcb +assets/shaders/ink_sparkle.frag,1768586303187,591c7517d5cb43eb91ea451e0d3f9f585cbf8298cf6c46a9144b77cb0775a406 +assets/fonts/MaterialIcons-Regular.otf,1768586306096,33efc485968dd28630ace587c22d6df359c195821b1114aaa85383e4d5394eac +assets/NOTICES,1768586302954,fc20c3c3c998057eb7e58ad2e009c7268bf748bfde685e95130431f4c54bd51c +main.dart.js,1768586301774,9b399ba21ab3247d46cf7dbcd5873aa248636bcd7864a1a0cedf1aae08608f9a diff --git a/em2rp/lib/models/equipment_model.dart b/em2rp/lib/models/equipment_model.dart index 56df85b..bfc3fa3 100644 --- a/em2rp/lib/models/equipment_model.dart +++ b/em2rp/lib/models/equipment_model.dart @@ -56,6 +56,7 @@ enum EquipmentCategory { consumable, // Consommable cable, // Câble vehicle, // Véhicule + backline, // Régie / Backline other // Autre } @@ -75,6 +76,8 @@ String equipmentCategoryToString(EquipmentCategory category) { return 'CABLE'; case EquipmentCategory.vehicle: return 'VEHICLE'; + case EquipmentCategory.backline: + return 'BACKLINE'; case EquipmentCategory.other: return 'OTHER'; case EquipmentCategory.effect: @@ -98,6 +101,8 @@ EquipmentCategory equipmentCategoryFromString(String? category) { return EquipmentCategory.cable; case 'VEHICLE': return EquipmentCategory.vehicle; + case 'BACKLINE': + return EquipmentCategory.backline; case 'EFFECT': return EquipmentCategory.effect; case 'OTHER': @@ -127,6 +132,8 @@ extension EquipmentCategoryExtension on EquipmentCategory { return 'Câble'; case EquipmentCategory.vehicle: return 'Véhicule'; + case EquipmentCategory.backline: + return 'Régie / Backline'; case EquipmentCategory.other: return 'Autre'; } @@ -151,6 +158,8 @@ extension EquipmentCategoryExtension on EquipmentCategory { return Icons.cable; case EquipmentCategory.vehicle: return Icons.local_shipping; + case EquipmentCategory.backline: + return Icons.piano; case EquipmentCategory.other: return Icons.more_horiz; } @@ -175,6 +184,8 @@ extension EquipmentCategoryExtension on EquipmentCategory { return Colors.grey; case EquipmentCategory.vehicle: return Colors.teal; + case EquipmentCategory.backline: + return Colors.indigo; case EquipmentCategory.other: return Colors.blueGrey; } @@ -193,6 +204,7 @@ extension EquipmentCategoryExtension on EquipmentCategory { case EquipmentCategory.effect: case EquipmentCategory.cable: case EquipmentCategory.vehicle: + case EquipmentCategory.backline: case EquipmentCategory.other: return null; } @@ -312,6 +324,7 @@ class EquipmentModel { final String? brand; // Marque (indexé) final String? model; // Modèle (indexé) final EquipmentCategory category; // Catégorie + final String? subCategory; // Sous-catégorie (indexé par catégorie) final EquipmentStatus status; // Statut actuel // Prix (visible uniquement avec manage_equipment) @@ -323,8 +336,6 @@ class EquipmentModel { final int? availableQuantity; // Quantité disponible final int? criticalThreshold; // Seuil critique pour alerte - // Boîtes parentes (plusieurs possibles) - final List parentBoxIds; // IDs des boîtes contenant cet équipement // Caractéristiques physiques final double? weight; // Poids (kg) @@ -354,13 +365,13 @@ class EquipmentModel { this.brand, this.model, required this.category, + this.subCategory, this.status = EquipmentStatus.available, this.purchasePrice, this.rentalPrice, this.totalQuantity, this.availableQuantity, this.criticalThreshold, - this.parentBoxIds = const [], this.weight, this.length, this.width, @@ -385,9 +396,6 @@ class EquipmentModel { } // Gestion des listes - final List parentBoxIdsRaw = map['parentBoxIds'] ?? []; - final List parentBoxIds = parentBoxIdsRaw.map((e) => e.toString()).toList(); - final List maintenanceIdsRaw = map['maintenanceIds'] ?? []; final List maintenanceIds = maintenanceIdsRaw.map((e) => e.toString()).toList(); @@ -397,13 +405,13 @@ class EquipmentModel { brand: map['brand'], model: map['model'], category: equipmentCategoryFromString(map['category']), + subCategory: map['subCategory'], status: equipmentStatusFromString(map['status']), purchasePrice: map['purchasePrice']?.toDouble(), rentalPrice: map['rentalPrice']?.toDouble(), totalQuantity: map['totalQuantity']?.toInt(), availableQuantity: map['availableQuantity']?.toInt(), criticalThreshold: map['criticalThreshold']?.toInt(), - parentBoxIds: parentBoxIds, weight: map['weight']?.toDouble(), length: map['length']?.toDouble(), width: map['width']?.toDouble(), @@ -424,13 +432,13 @@ class EquipmentModel { 'brand': brand, 'model': model, 'category': equipmentCategoryToString(category), + 'subCategory': subCategory, 'status': equipmentStatusToString(status), 'purchasePrice': purchasePrice, 'rentalPrice': rentalPrice, 'totalQuantity': totalQuantity, 'availableQuantity': availableQuantity, 'criticalThreshold': criticalThreshold, - 'parentBoxIds': parentBoxIds, 'weight': weight, 'length': length, 'width': width, @@ -452,13 +460,13 @@ class EquipmentModel { String? name, String? model, EquipmentCategory? category, + String? subCategory, EquipmentStatus? status, double? purchasePrice, double? rentalPrice, int? totalQuantity, int? availableQuantity, int? criticalThreshold, - List? parentBoxIds, double? weight, double? length, double? width, @@ -478,13 +486,13 @@ class EquipmentModel { name: name ?? this.name, model: model ?? this.model, category: category ?? this.category, + subCategory: subCategory ?? this.subCategory, status: status ?? this.status, purchasePrice: purchasePrice ?? this.purchasePrice, rentalPrice: rentalPrice ?? this.rentalPrice, totalQuantity: totalQuantity ?? this.totalQuantity, availableQuantity: availableQuantity ?? this.availableQuantity, criticalThreshold: criticalThreshold ?? this.criticalThreshold, - parentBoxIds: parentBoxIds ?? this.parentBoxIds, weight: weight ?? this.weight, length: length ?? this.length, width: width ?? this.width, diff --git a/em2rp/lib/providers/equipment_provider.dart b/em2rp/lib/providers/equipment_provider.dart index 3fe8217..c4cb556 100644 --- a/em2rp/lib/providers/equipment_provider.dart +++ b/em2rp/lib/providers/equipment_provider.dart @@ -94,7 +94,6 @@ class EquipmentProvider extends ChangeNotifier { name: '', category: EquipmentCategory.other, status: EquipmentStatus.available, - parentBoxIds: [], maintenanceIds: [], createdAt: DateTime.now(), updatedAt: DateTime.now(), @@ -287,6 +286,18 @@ class EquipmentProvider extends ChangeNotifier { return modelsByBrand; } + /// Charger les sous-catégories d'une catégorie spécifique + Future> loadSubCategoriesByCategory(EquipmentCategory category) async { + // Filtrer les sous-catégories par catégorie + final subCategoriesByCategory = _equipment + .where((eq) => eq.category == category && eq.subCategory != null && eq.subCategory!.isNotEmpty) + .map((eq) => eq.subCategory!) + .toSet() + .toList() + ..sort(); + return subCategoriesByCategory; + } + /// Calculer le statut réel d'un équipement (compatibilité) Future calculateRealStatus(EquipmentModel equipment) async { // Pour l'instant, retourner le statut stocké diff --git a/em2rp/lib/services/equipment_service.dart b/em2rp/lib/services/equipment_service.dart index c2bcc58..cbc05f2 100644 --- a/em2rp/lib/services/equipment_service.dart +++ b/em2rp/lib/services/equipment_service.dart @@ -313,6 +313,30 @@ class EquipmentService { } } + /// Récupérer les sous-catégories filtrées par catégorie + Future> getSubCategoriesByCategory(EquipmentCategory category) async { + try { + final equipmentsData = await _dataService.getEquipments(); + final subCategories = {}; + + final categoryString = equipmentCategoryToString(category); + + for (var data in equipmentsData) { + if (data['category'] == categoryString) { + final subCategory = data['subCategory'] as String?; + if (subCategory != null && subCategory.isNotEmpty) { + subCategories.add(subCategory); + } + } + } + + return subCategories.toList()..sort(); + } catch (e) { + print('Error getting subcategories by category: $e'); + rethrow; + } + } + /// Vérifier si un ID existe déjà Future isIdUnique(String id) async { try { diff --git a/em2rp/lib/views/container_detail_page.dart b/em2rp/lib/views/container_detail_page.dart index 399a015..d1ce6fe 100644 --- a/em2rp/lib/views/container_detail_page.dart +++ b/em2rp/lib/views/container_detail_page.dart @@ -624,6 +624,8 @@ class _ContainerDetailPageState extends State { return 'Câble'; case EquipmentCategory.vehicle: return 'Véhicule'; + case EquipmentCategory.backline: + return 'Régie / Backline'; case EquipmentCategory.other: return 'Autre'; } diff --git a/em2rp/lib/views/container_form_page.dart b/em2rp/lib/views/container_form_page.dart index 034e89e..9ac9659 100644 --- a/em2rp/lib/views/container_form_page.dart +++ b/em2rp/lib/views/container_form_page.dart @@ -914,6 +914,8 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> { return 'Câble'; case EquipmentCategory.vehicle: return 'Véhicule'; + case EquipmentCategory.backline: + return 'Régie / Backline'; case EquipmentCategory.other: return 'Autre'; } @@ -937,6 +939,8 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> { return Icons.cable; case EquipmentCategory.vehicle: return Icons.local_shipping; + case EquipmentCategory.backline: + return Icons.piano; case EquipmentCategory.other: return Icons.category; } diff --git a/em2rp/lib/views/container_management_page.dart b/em2rp/lib/views/container_management_page.dart index f5c07cf..a2629a6 100644 --- a/em2rp/lib/views/container_management_page.dart +++ b/em2rp/lib/views/container_management_page.dart @@ -707,7 +707,6 @@ class _ContainerManagementPageState extends State name: '', category: EquipmentCategory.other, status: EquipmentStatus.available, - parentBoxIds: [], maintenanceIds: [], createdAt: DateTime.now(), updatedAt: DateTime.now(), diff --git a/em2rp/lib/views/equipment_detail_page.dart b/em2rp/lib/views/equipment_detail_page.dart index e5153f5..3b0a223 100644 --- a/em2rp/lib/views/equipment_detail_page.dart +++ b/em2rp/lib/views/equipment_detail_page.dart @@ -249,6 +249,17 @@ class _EquipmentDetailPageState extends State { '${widget.equipment.brand ?? ''} ${widget.equipment.model ?? ''}'.trim(), style: TextStyle(color: Colors.grey[700]), ), + if (widget.equipment.subCategory != null && widget.equipment.subCategory!.isNotEmpty) ...[ + const SizedBox(height: 4), + Text( + '📁 ${widget.equipment.subCategory}', + style: TextStyle( + color: Colors.grey[600], + fontSize: 13, + fontStyle: FontStyle.italic, + ), + ), + ], ], ), ), diff --git a/em2rp/lib/views/equipment_form/subcategory_selector.dart b/em2rp/lib/views/equipment_form/subcategory_selector.dart new file mode 100644 index 0000000..9447000 --- /dev/null +++ b/em2rp/lib/views/equipment_form/subcategory_selector.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:em2rp/models/equipment_model.dart'; + +/// Widget de sélection de sous-catégorie avec autocomplétion +/// Similaire au système Brand/Model mais filtré par catégorie +class SubCategorySelector extends StatelessWidget { + final TextEditingController controller; + final EquipmentCategory? selectedCategory; + final List filteredSubCategories; + final ValueChanged? onChanged; + + const SubCategorySelector({ + super.key, + required this.controller, + required this.selectedCategory, + required this.filteredSubCategories, + this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return Autocomplete( + initialValue: TextEditingValue(text: controller.text), + optionsBuilder: (TextEditingValue textEditingValue) { + if (selectedCategory == null) { + return const Iterable.empty(); + } + if (textEditingValue.text.isEmpty) { + return filteredSubCategories; + } + return filteredSubCategories.where((String subCategory) { + return subCategory.toLowerCase().contains( + textEditingValue.text.toLowerCase(), + ); + }); + }, + onSelected: (String selection) { + controller.text = selection; + onChanged?.call(selection); + }, + fieldViewBuilder: (context, fieldController, focusNode, onEditingComplete) { + if (fieldController.text != controller.text) { + fieldController.text = controller.text; + } + return TextFormField( + controller: fieldController, + focusNode: focusNode, + enabled: selectedCategory != null, + decoration: InputDecoration( + labelText: 'Sous-catégorie', + border: const OutlineInputBorder(), + prefixIcon: const Icon(Icons.category_outlined), + hintText: selectedCategory == null + ? 'Catégorie requise' + : 'Saisissez la sous-catégorie', + helperText: 'Optionnel - Permet un classement plus précis', + ), + onChanged: (value) { + controller.text = value; + onChanged?.call(value.isNotEmpty ? value : null); + }, + ); + }, + ); + } +} diff --git a/em2rp/lib/views/equipment_form_page.dart b/em2rp/lib/views/equipment_form_page.dart index 72be0b8..facb91b 100644 --- a/em2rp/lib/views/equipment_form_page.dart +++ b/em2rp/lib/views/equipment_form_page.dart @@ -2,19 +2,16 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/models/equipment_model.dart'; -import 'package:em2rp/models/container_model.dart'; import 'package:em2rp/providers/equipment_provider.dart'; -import 'package:em2rp/providers/container_provider.dart'; import 'package:em2rp/providers/local_user_provider.dart'; import 'package:em2rp/services/equipment_service.dart'; -import 'package:em2rp/services/container_equipment_service.dart'; import 'package:em2rp/utils/colors.dart'; import 'package:em2rp/views/widgets/nav/custom_app_bar.dart'; import 'package:intl/intl.dart'; import 'package:em2rp/views/equipment_form/brand_model_selector.dart'; +import 'package:em2rp/views/equipment_form/subcategory_selector.dart'; import 'package:em2rp/utils/id_generator.dart'; import 'package:em2rp/utils/debug_log.dart'; -import 'package:em2rp/views/widgets/equipment/parent_boxes_selector.dart'; class EquipmentFormPage extends StatefulWidget { final EquipmentModel? equipment; @@ -33,6 +30,7 @@ class _EquipmentFormPageState extends State { final TextEditingController _identifierController = TextEditingController(); final TextEditingController _brandController = TextEditingController(); final TextEditingController _modelController = TextEditingController(); + final TextEditingController _subCategoryController = TextEditingController(); final TextEditingController _purchasePriceController = TextEditingController(); final TextEditingController _rentalPriceController = TextEditingController(); final TextEditingController _totalQuantityController = TextEditingController(); @@ -46,18 +44,15 @@ class _EquipmentFormPageState extends State { DateTime? _purchaseDate; DateTime? _lastMaintenanceDate; DateTime? _nextMaintenanceDate; - List _selectedParentBoxIds = []; - List _availableBoxes = []; bool _isLoading = false; - bool _isLoadingBoxes = true; bool _addMultiple = false; String? _selectedBrand; List _filteredModels = []; + List _filteredSubCategories = []; @override void initState() { super.initState(); - _loadAvailableBoxes(); WidgetsBinding.instance.addPostFrameCallback((_) { final provider = Provider.of(context, listen: false); provider.loadBrands(); @@ -75,6 +70,7 @@ class _EquipmentFormPageState extends State { _brandController.text = equipment.brand ?? ''; _selectedBrand = equipment.brand; _modelController.text = equipment.model ?? ''; + _subCategoryController.text = equipment.subCategory ?? ''; _selectedCategory = equipment.category; _selectedStatus = equipment.status; _purchasePriceController.text = equipment.purchasePrice?.toStringAsFixed(2) ?? ''; @@ -89,51 +85,15 @@ class _EquipmentFormPageState extends State { DebugLog.info('[EquipmentForm] Populating fields for equipment: ${equipment.id}'); - // Charger les containers contenant cet équipement depuis Firestore - _loadCurrentContainers(equipment.id); if (_selectedBrand != null && _selectedBrand!.isNotEmpty) { _loadFilteredModels(_selectedBrand!); } + + // Charger les sous-catégories pour la catégorie sélectionnée + _loadFilteredSubCategories(_selectedCategory); } - /// Charge les containers qui contiennent actuellement cet équipement - Future _loadCurrentContainers(String equipmentId) async { - try { - final containers = await containerEquipmentService.getContainersByEquipment(equipmentId); - setState(() { - _selectedParentBoxIds = containers.map((c) => c.id).toList(); - }); - DebugLog.info('[EquipmentForm] Loaded ${containers.length} containers for equipment $equipmentId'); - DebugLog.info('[EquipmentForm] Selected container IDs: $_selectedParentBoxIds'); - } catch (e) { - DebugLog.error('[EquipmentForm] Error loading containers for equipment', e); - } - } - - Future _loadAvailableBoxes() async { - try { - final boxes = await _equipmentService.getBoxes(); - DebugLog.info('[EquipmentForm] Loaded ${boxes.length} boxes from service'); - for (var box in boxes) { - DebugLog.info('[EquipmentForm] Box loaded - ID: ${box.id}, Name: ${box.name}'); - } - setState(() { - _availableBoxes = boxes; - _isLoadingBoxes = false; - }); - } catch (e) { - DebugLog.error('[EquipmentForm] Error loading boxes', e); - setState(() { - _isLoadingBoxes = false; - }); - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Erreur lors du chargement des boîtes : $e')), - ); - } - } - } Future _loadFilteredModels(String brand) async { try { @@ -149,11 +109,26 @@ class _EquipmentFormPageState extends State { } } + Future _loadFilteredSubCategories(EquipmentCategory category) async { + try { + final equipmentProvider = Provider.of(context, listen: false); + final subCategories = await equipmentProvider.loadSubCategoriesByCategory(category); + setState(() { + _filteredSubCategories = subCategories; + }); + } catch (e) { + setState(() { + _filteredSubCategories = []; + }); + } + } + @override void dispose() { _identifierController.dispose(); _brandController.dispose(); _modelController.dispose(); + _subCategoryController.dispose(); _purchasePriceController.dispose(); _rentalPriceController.dispose(); _totalQuantityController.dispose(); @@ -312,7 +287,9 @@ class _EquipmentFormPageState extends State { if (value != null) { setState(() { _selectedCategory = value; + _subCategoryController.clear(); }); + _loadFilteredSubCategories(value); } }, ), @@ -348,6 +325,19 @@ class _EquipmentFormPageState extends State { ), const SizedBox(height: 16), + // Sous-catégorie + SubCategorySelector( + controller: _subCategoryController, + selectedCategory: _selectedCategory, + filteredSubCategories: _filteredSubCategories, + onChanged: (value) { + setState(() { + // La valeur est déjà dans le controller + }); + }, + ), + const SizedBox(height: 16), + // Prix if (hasManagePermission) ...[ Row( @@ -419,18 +409,6 @@ class _EquipmentFormPageState extends State { const SizedBox(height: 16), ], - // Boîtes parentes - const SizedBox(height: 8), - _isLoadingBoxes - ? const Card( - child: Padding( - padding: EdgeInsets.all(32.0), - child: Center(child: CircularProgressIndicator()), - ), - ) - : _buildParentBoxesSelector(), - const SizedBox(height: 16), - // Dates const Divider(), const Text('Dates', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), @@ -481,17 +459,6 @@ class _EquipmentFormPageState extends State { ); } - Widget _buildParentBoxesSelector() { - return ParentBoxesSelector( - availableBoxes: _availableBoxes, - selectedBoxIds: _selectedParentBoxIds, - onSelectionChanged: (newSelection) { - setState(() { - _selectedParentBoxIds = newSelection; - }); - }, - ); - } Widget _buildDateField({required String label, required IconData icon, required DateTime? value, required VoidCallback onTap}) { return InkWell( @@ -629,6 +596,7 @@ class _EquipmentFormPageState extends State { brand: brand, model: model, category: _selectedCategory, + subCategory: _subCategoryController.text.trim().isNotEmpty ? _subCategoryController.text.trim() : null, status: _selectedStatus, purchasePrice: _purchasePriceController.text.isNotEmpty ? double.tryParse(_purchasePriceController.text) : null, rentalPrice: _rentalPriceController.text.isNotEmpty ? double.tryParse(_rentalPriceController.text) : null, @@ -637,7 +605,6 @@ class _EquipmentFormPageState extends State { purchaseDate: _purchaseDate, lastMaintenanceDate: _lastMaintenanceDate, nextMaintenanceDate: _nextMaintenanceDate, - parentBoxIds: [], // On ne stocke plus les parentBoxIds dans l'équipement notes: _notesController.text, createdAt: isEditing ? (widget.equipment?.createdAt ?? now) : now, updatedAt: now, @@ -645,58 +612,8 @@ class _EquipmentFormPageState extends State { ); if (isEditing) { await equipmentProvider.updateEquipment(equipment); - - // Synchroniser les containers : mettre à jour equipmentIds des containers - // Charger les anciens containers depuis Firestore - final oldContainers = await containerEquipmentService.getContainersByEquipment(equipment.id); - final oldParentBoxIds = oldContainers.map((c) => c.id).toList(); - final newParentBoxIds = _selectedParentBoxIds; - - // Boîtes ajoutées : ajouter cet équipement à leur equipmentIds - final addedBoxes = newParentBoxIds.where((id) => !oldParentBoxIds.contains(id)); - for (final boxId in addedBoxes) { - try { - final containerProvider = Provider.of(context, listen: false); - await containerProvider.addEquipmentToContainer( - containerId: boxId, - equipmentId: equipment.id, - ); - DebugLog.info('[EquipmentForm] Added equipment ${equipment.id} to container $boxId'); - } catch (e) { - DebugLog.error('[EquipmentForm] Error adding equipment to container $boxId', e); - } - } - - // Boîtes retirées : retirer cet équipement de leur equipmentIds - final removedBoxes = oldParentBoxIds.where((id) => !newParentBoxIds.contains(id)); - for (final boxId in removedBoxes) { - try { - final containerProvider = Provider.of(context, listen: false); - await containerProvider.removeEquipmentFromContainer( - containerId: boxId, - equipmentId: equipment.id, - ); - DebugLog.info('[EquipmentForm] Removed equipment ${equipment.id} from container $boxId'); - } catch (e) { - DebugLog.error('[EquipmentForm] Error removing equipment from container $boxId', e); - } - } } else { await equipmentProvider.addEquipment(equipment); - - // Pour un nouvel équipement, ajouter à tous les containers sélectionnés - for (final boxId in _selectedParentBoxIds) { - try { - final containerProvider = Provider.of(context, listen: false); - await containerProvider.addEquipmentToContainer( - containerId: boxId, - equipmentId: equipment.id, - ); - DebugLog.info('[EquipmentForm] Added new equipment ${equipment.id} to container $boxId'); - } catch (e) { - DebugLog.error('[EquipmentForm] Error adding new equipment to container $boxId', e); - } - } } } diff --git a/em2rp/lib/views/equipment_management_page.dart b/em2rp/lib/views/equipment_management_page.dart index 5a2c9d8..22d368d 100644 --- a/em2rp/lib/views/equipment_management_page.dart +++ b/em2rp/lib/views/equipment_management_page.dart @@ -559,6 +559,18 @@ class _EquipmentManagementPageState extends State : 'Marque/Modèle non défini', style: TextStyle(color: Colors.grey[600], fontSize: 14), ), + // Afficher la sous-catégorie si elle existe + if (equipment.subCategory != null && equipment.subCategory!.isNotEmpty) ...[ + const SizedBox(height: 2), + Text( + '📁 ${equipment.subCategory}', + style: TextStyle( + color: Colors.grey[500], + fontSize: 12, + fontStyle: FontStyle.italic, + ), + ), + ], // Afficher la quantité disponible pour les consommables/câbles if (equipment.category == EquipmentCategory.consumable || equipment.category == EquipmentCategory.cable) ...[ @@ -1099,7 +1111,6 @@ class _EquipmentManagementPageState extends State name: '', category: EquipmentCategory.other, status: EquipmentStatus.available, - parentBoxIds: [], maintenanceIds: [], createdAt: DateTime.now(), updatedAt: DateTime.now(), diff --git a/em2rp/lib/views/event_preparation_page.dart b/em2rp/lib/views/event_preparation_page.dart index 8c39bb2..fc7ea74 100644 --- a/em2rp/lib/views/event_preparation_page.dart +++ b/em2rp/lib/views/event_preparation_page.dart @@ -165,7 +165,6 @@ class _EventPreparationPageState extends State with Single name: 'Équipement inconnu', category: EquipmentCategory.other, status: EquipmentStatus.available, - parentBoxIds: [], maintenanceIds: [], createdAt: DateTime.now(), updatedAt: DateTime.now(), diff --git a/em2rp/lib/views/widgets/containers/container_equipment_tile.dart b/em2rp/lib/views/widgets/containers/container_equipment_tile.dart index 6c2b163..ef1b2b2 100644 --- a/em2rp/lib/views/widgets/containers/container_equipment_tile.dart +++ b/em2rp/lib/views/widgets/containers/container_equipment_tile.dart @@ -104,6 +104,8 @@ class ContainerEquipmentTile extends StatelessWidget { return 'Câble'; case EquipmentCategory.vehicle: return 'Véhicule'; + case EquipmentCategory.backline: + return 'Régie / Backline'; case EquipmentCategory.other: return 'Autre'; } diff --git a/em2rp/lib/views/widgets/event/equipment_selection_dialog.dart b/em2rp/lib/views/widgets/event/equipment_selection_dialog.dart index 084752f..ba55421 100644 --- a/em2rp/lib/views/widgets/event/equipment_selection_dialog.dart +++ b/em2rp/lib/views/widgets/event/equipment_selection_dialog.dart @@ -766,7 +766,6 @@ class _EquipmentSelectionDialogState extends State { name: 'Inconnu', category: EquipmentCategory.other, status: EquipmentStatus.available, - parentBoxIds: [], maintenanceIds: [], createdAt: DateTime.now(), updatedAt: DateTime.now(), @@ -1156,7 +1155,6 @@ class _EquipmentSelectionDialogState extends State { name: '', category: EquipmentCategory.other, status: EquipmentStatus.available, - parentBoxIds: [], maintenanceIds: [], createdAt: DateTime.now(), updatedAt: DateTime.now(), diff --git a/em2rp/lib/views/widgets/event_form/event_assigned_equipment_section.dart b/em2rp/lib/views/widgets/event_form/event_assigned_equipment_section.dart index 10fa448..3b1b698 100644 --- a/em2rp/lib/views/widgets/event_form/event_assigned_equipment_section.dart +++ b/em2rp/lib/views/widgets/event_form/event_assigned_equipment_section.dart @@ -84,7 +84,6 @@ class _EventAssignedEquipmentSectionState extends State