diff --git a/lib/features/operations/blocs/operation_form_cubit.dart b/lib/features/operations/blocs/operation_form_cubit.dart index 1734702..cc97193 100644 --- a/lib/features/operations/blocs/operation_form_cubit.dart +++ b/lib/features/operations/blocs/operation_form_cubit.dart @@ -273,7 +273,6 @@ class OperationFormCubit extends Cubit { final updatedOperation = current.copyWith( // Se newProvider è null, passiamo una funzione che ritorna null per sbiancare i campi! - providerId: () => newProvider?.id, provider: () => newProvider, ); @@ -379,7 +378,6 @@ class OperationFormCubit extends Cubit { defaultDate, // Impostiamo la scadenza di default se calcolata // 🥷 APPLICHIAMO IL TRUCCO NINJA DELLE FUNZIONI // Se targetProvider è null, le funzioni ritorneranno null sbiancando il DB! - providerId: () => targetProvider?.id, provider: () => targetProvider, // Nota: Per azzerare davvero questi due, ricordati in futuro di applicare diff --git a/lib/features/operations/data/operations_repository.dart b/lib/features/operations/data/operations_repository.dart index 6895395..366f456 100644 --- a/lib/features/operations/data/operations_repository.dart +++ b/lib/features/operations/data/operations_repository.dart @@ -59,7 +59,7 @@ class OperationsRepository { *, ${Tables.customers}(*), ${Tables.stores}(name), - ${Tables.providers}(name, color_hex), + ${Tables.providers}(*), ${Tables.models}(name_with_brand), ${Tables.staffMembers}(name), ${Tables.attachments}(*) diff --git a/lib/features/operations/models/operation_model.dart b/lib/features/operations/models/operation_model.dart index 25aaf6c..6113674 100644 --- a/lib/features/operations/models/operation_model.dart +++ b/lib/features/operations/models/operation_model.dart @@ -30,7 +30,6 @@ class OperationModel extends Equatable { final DateTime? createdAt; final String type; final String? subType; - final String? providerId; final String? modelId; final String? modelDisplayName; final String? description; @@ -60,7 +59,6 @@ class OperationModel extends Equatable { this.createdAt, this.type = '', this.subType, - this.providerId, this.modelId, this.modelDisplayName, this.description, @@ -90,7 +88,6 @@ class OperationModel extends Equatable { String? type, String? subType, // 🥷 TRUCCO APPLICATO ANCHE QUI: - String? Function()? providerId, ProviderModel? Function()? provider, String? modelId, String? modelDisplayName, @@ -118,7 +115,6 @@ class OperationModel extends Equatable { type: type ?? this.type, subType: subType ?? this.subType, // Se la funzione è passata, la eseguiamo (anche se ritorna null), altrimenti teniamo il vecchio - providerId: providerId != null ? providerId() : this.providerId, provider: provider != null ? provider() : this.provider, modelId: modelId ?? this.modelId, @@ -149,7 +145,6 @@ class OperationModel extends Equatable { createdAt, type, subType, - providerId, provider, modelId, modelDisplayName, @@ -187,8 +182,6 @@ class OperationModel extends Equatable { subType: map['sub_type'] as String?, // I campi relazionali nullabili restano rigorosamente null! - providerId: map['provider_id'] as String?, - // MAGIA ANTI-CRASH: Usiamo ?['chiave'] per non far esplodere i join vuoti provider: (map[Tables.providers] != null) ? ProviderModel.fromMap(map[Tables.providers] as Map) : null, @@ -243,7 +236,7 @@ class OperationModel extends Equatable { if (id != null) 'id': id, 'type': type, 'sub_type': subType, - 'provider_id': providerId, + 'provider_id': provider?.id, 'model_id': modelId, 'description': description, if (expirationDate != null) diff --git a/lib/features/operations/ui/operation_list_screen.dart b/lib/features/operations/ui/operation_list_screen.dart index eb5b83d..c4d80d6 100644 --- a/lib/features/operations/ui/operation_list_screen.dart +++ b/lib/features/operations/ui/operation_list_screen.dart @@ -571,7 +571,7 @@ class _RichOperationCard extends StatelessWidget { ), // Tag Gestore (Agganciato dinamicamente al displayColor generato dall'esadecimale del DB!) - if (operation.providerId != null) + if (operation.provider != null) _MiniChip( label: operation.provider?.name ?? 'Gestore', color: diff --git a/lib/features/operations/ui/widgets/details_section.dart b/lib/features/operations/ui/widgets/details_section.dart index fa624b8..ff23429 100644 --- a/lib/features/operations/ui/widgets/details_section.dart +++ b/lib/features/operations/ui/widgets/details_section.dart @@ -138,13 +138,13 @@ class OperationDetailsSection extends StatelessWidget { : 'Nessun gestore selezionato', style: TextStyle( color: - (currentOp?.providerId == null || - currentOp!.providerId!.isEmpty) + (currentOp?.provider == null || + currentOp!.provider!.name.isEmpty) ? Colors.grey : null, fontWeight: - (currentOp?.providerId == null || - currentOp!.providerId!.isEmpty) + (currentOp?.provider == null || + currentOp!.provider!.name.isEmpty) ? FontWeight.normal : FontWeight.bold, ), diff --git a/lib/features/tasks/blocs/task_form_cubit.dart b/lib/features/tasks/blocs/task_form_cubit.dart index e76f6d7..7f92553 100644 --- a/lib/features/tasks/blocs/task_form_cubit.dart +++ b/lib/features/tasks/blocs/task_form_cubit.dart @@ -58,6 +58,7 @@ class TaskFormCubit extends Cubit { dueDate: task.dueDate, isGlobal: task.isGlobal, // Sfrutta il tuo getter storeId == null selectedStaffIds: task.assignedToIds, + taskStatus: task.status, ), ); await _loadExistingTaskReminders(task.id!); @@ -272,6 +273,10 @@ class TaskFormCubit extends Cubit { } } + Future updateTaskLocalStatus(TaskStatus newStatus) async { + emit(state.copyWith(taskStatus: newStatus)); + } + Future updateTaskStatus(TaskStatus newStatus) async { try { // Chiamiamo il repo passando il task aggiornato diff --git a/lib/features/tasks/models/task_model.dart b/lib/features/tasks/models/task_model.dart index ee932a6..a2c386e 100644 --- a/lib/features/tasks/models/task_model.dart +++ b/lib/features/tasks/models/task_model.dart @@ -1,5 +1,4 @@ import 'package:equatable/equatable.dart'; -import 'package:flux/core/utils/extensions.dart'; import 'package:flux/features/master_data/staff/models/staff_member_model.dart'; import 'package:flux/features/tasks/models/task_status.dart'; diff --git a/lib/features/tasks/models/task_status.dart b/lib/features/tasks/models/task_status.dart index e0bb286..58044ff 100644 --- a/lib/features/tasks/models/task_status.dart +++ b/lib/features/tasks/models/task_status.dart @@ -2,7 +2,7 @@ enum TaskStatus { open, inProgress, completed } extension TaskStatusExtension on TaskStatus { - String get name { + String get displayName { switch (this) { case TaskStatus.open: return 'Da Iniziare'; diff --git a/lib/features/tasks/ui/task_form_screen.dart b/lib/features/tasks/ui/task_form_screen.dart index 0d6048a..e656995 100644 --- a/lib/features/tasks/ui/task_form_screen.dart +++ b/lib/features/tasks/ui/task_form_screen.dart @@ -124,6 +124,30 @@ class _TaskFormScreenState extends State { appBar: AppBar( title: Text(isEditing ? 'Modifica Task' : 'Nuovo Task'), actions: [ + // 🥷 1. BOTTONE COMPLETAMENTO RAPIDO (Solo se in edit e non già completato) + if (isEditing && state.taskStatus != TaskStatus.completed) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 8.0, + ), + child: ElevatedButton.icon( + onPressed: () { + context.read().updateTaskStatus( + TaskStatus.completed, + ); + }, + icon: const Icon(Icons.check_circle_outline), + label: const Text('Completa'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green.shade600, + foregroundColor: Colors.white, + elevation: 0, + ), + ), + ), + + // 🥷 2. LOADER O BOTTONE SALVA if (state.status == TaskFormStatus.submitting) const Padding( padding: EdgeInsets.all(16.0), @@ -134,13 +158,18 @@ class _TaskFormScreenState extends State { ), ) else - TextButton.icon( - onPressed: state.isFormValid ? () => cubit.saveTask() : null, - icon: const Icon(Icons.save), - label: const Text('Salva'), - style: TextButton.styleFrom( - foregroundColor: Colors.orange, - disabledForegroundColor: Colors.grey, + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: TextButton.icon( + onPressed: state.isFormValid + ? () => cubit.saveTask() + : null, + icon: const Icon(Icons.save), + label: const Text('Salva'), + style: TextButton.styleFrom( + foregroundColor: Colors.orange, + disabledForegroundColor: Colors.grey, + ), ), ), ], @@ -183,43 +212,6 @@ class _TaskFormScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (state.id != null && - state.taskStatus != TaskStatus.completed) - Container( - margin: const EdgeInsets.only(bottom: 24.0), - width: double.infinity, - child: ElevatedButton.icon( - onPressed: () { - // Chiama direttamente l'update immediato nel DB! - context - .read() - .updateTaskStatus(TaskStatus.completed); - }, - icon: const Icon( - Icons.check_circle_outline, - size: 28, - ), - label: const Text( - 'Segna come Completato', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.green.shade600, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric( - vertical: 16, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 2, - ), - ), - ), - const Divider(height: 30), _buildFormFields(context, state, cubit), const SizedBox(height: 30), ElevatedButton.icon( @@ -302,6 +294,45 @@ class _TaskFormScreenState extends State { ), onChanged: cubit.updateDescription, ), + if (state.id != null) ...[ + const SizedBox(height: 16), + DropdownButtonFormField( + // Leggiamo lo stato attuale dal Cubit (o usiamo un default per i nuovi task) + initialValue: state.taskStatus, + + decoration: InputDecoration( + labelText: 'Stato Attuale', + prefixIcon: const Icon(Icons.flag_outlined), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + + // Mappiamo tutti i valori dell'enum in elementi della tendina + items: TaskStatus.values.map((TaskStatus status) { + return DropdownMenuItem( + value: status, + child: Text( + status + .displayName, // Usa la property displayName del tuo enum! + style: TextStyle( + fontWeight: status == state.taskStatus + ? FontWeight.bold + : FontWeight.normal, + ), + ), + ); + }).toList(), + + onChanged: (TaskStatus? newStatus) { + if (newStatus != null && newStatus != state.taskStatus) { + context.read().updateTaskStatus(newStatus); + } + }, + ), + ], const SizedBox(height: 24), // --- SCADENZA --- diff --git a/pubspec.lock b/pubspec.lock index 15e9f8f..aa77f86 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "8f89e371e2883de35cdc78f648e725fa4da5f3b6c927269f00fa68f1ea92b598" + sha256: "0d1f0adfabbab9f46a1a80ce84a4d8b852b6e4dbf53ce413b30e0cf7d3631b71" url: "https://pub.dev" source: hosted - version: "1.3.71" + version: "1.3.72" app_links: dependency: transitive description: name: app_links - sha256: "3462d9defc61565fde4944858b59bec5be2b9d5b05f20aed190adb3ad08a7abc" + sha256: a350a5b37579b7227aaf9a59c07114617cd4283852e193f743b2b3d2d7483c18 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.1.1" app_links_linux: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: code_assets - sha256: dad6bf6b9f4f378b0a69edbf42584d336efd1a9ce15deb1ba591cbb1b5ff440f + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" collection: dependency: "direct main" description: @@ -181,10 +181,10 @@ packages: dependency: transitive description: name: dbus - sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + sha256: "0ce9b0a839e6dee59a37a623d2fc26a35bbbe6404213e419b0d6411023d62645" url: "https://pub.dev" source: hosted - version: "0.7.12" + version: "0.7.14" equatable: dependency: "direct main" description: @@ -269,10 +269,10 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "93a5bde9775fd5adcc937f39dfa04ae0bc89c4d79bea6abc49de3f7b049d9ff6" + sha256: ec46a100a560d3bd5f97f2d89ba7492cb09b6dd0a4a28753d1258f360d6bd9f9 url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.10.0" firebase_core_platform_interface: dependency: transitive description: @@ -285,34 +285,34 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: "7c98f10b8c8e5adedc0b810b66a877120696675e2c22d9ca9caca092da0d9e57" + sha256: "5ad1be848692ec148f2d6a8ad2a3838cb852ea5f3c9e6479a7afce479e1854f8" url: "https://pub.dev" source: hosted - version: "3.7.0" + version: "3.8.0" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "8d0dc81a31cd030170508dc3e89bfd14355b20a1b991340af5f018e37daab5d7" + sha256: "9651e833454156b9f0927eaedccffba0f7f6a6e20ceddef82517211e7017e9c4" url: "https://pub.dev" source: hosted - version: "16.2.2" + version: "16.3.0" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: "37abb0b0535c5497605ee94c12470e1ebbbe47e71a22d0c20bffcc912311f8cb" + sha256: "292bb5dc9c4a429078895406c347d7c7690deb858c1adeed8f4b4346f769dfa3" url: "https://pub.dev" source: hosted - version: "4.7.11" + version: "4.8.0" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "54e22b43e2c26a2728a3f68c188de0f9011993ae19ae959a06d476dad935c776" + sha256: "08c565bc83729439f5de2dfea77b4832002b705eb2f840366cefa80e4e5c3c66" url: "https://pub.dev" source: hosted - version: "4.1.7" + version: "4.2.0" fixnum: dependency: transitive description: @@ -367,10 +367,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0" + sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" url: "https://pub.dev" source: hosted - version: "2.0.34" + version: "2.0.35" flutter_staggered_grid_view: dependency: "direct main" description: @@ -425,10 +425,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "92d8cee7c57dff0a6c409c05597b460002434eccf7424a712283225b3962d03f" + sha256: "5922b2861e2235a3504896f0d6fa07d84141b480cf52eecd2f42cd25585a9e8a" url: "https://pub.dev" source: hosted - version: "17.2.3" + version: "17.3.0" google_fonts: dependency: "direct main" description: @@ -457,10 +457,10 @@ packages: dependency: transitive description: name: hooks - sha256: a41af4e8fc687cd6d33de9751eb936c8c0204ebe2bcb6c15ecf707504bf47f31 + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.2" http: dependency: transitive description: @@ -497,10 +497,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: d5b3e1774af29c9ab00103afb0d4614070f924d2e0057ac867ec98800114793f + sha256: "6f3a1995eafb000333174fae92202622033b0ee7fd917a6cd3730295264df84a" url: "https://pub.dev" source: hosted - version: "0.8.13+17" + version: "0.8.13+19" image_picker_for_web: dependency: transitive description: @@ -802,10 +802,10 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 + sha256: fe54465bcc62a4564c6e4db337bbaded6c0c0fa6e10487414436d163114784f6 url: "https://pub.dev" source: hosted - version: "12.0.1" + version: "12.0.3" permission_handler_android: dependency: transitive description: @@ -818,10 +818,10 @@ packages: dependency: transitive description: name: permission_handler_apple - sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + sha256: e20daf680eef1ca62ffe8c8c526b778cc386d50137c77ac71c8ec9c88c13fb9d url: "https://pub.dev" source: hosted - version: "9.4.7" + version: "9.4.9" permission_handler_html: dependency: transitive description: @@ -986,10 +986,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + sha256: a2c49fc1fed7140cadd892d765bd47edbe4ac0b9c7e7e3c493dcb58126f99cf0 url: "https://pub.dev" source: hosted - version: "2.4.23" + version: "2.4.25" shared_preferences_foundation: dependency: transitive description: @@ -1095,10 +1095,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "63896c27e81b28f8cb4e69ead0d3e8f03f1d1e5fc531a3e579cabed6a2c7c9e5" + sha256: "93b153dcb6a26dcddee6ca087dd634b53e38c10b5aa163e8e49501a776456153" url: "https://pub.dev" source: hosted - version: "3.4.0+1" + version: "3.4.1" term_glyph: dependency: transitive description: @@ -1159,10 +1159,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" + sha256: b413d49b73867ac08dd2f9890efd3cc11f2a0e577618d50843440a1fb3776c32 url: "https://pub.dev" source: hosted - version: "6.3.30" + version: "6.3.32" url_launcher_ios: dependency: transitive description: @@ -1239,10 +1239,10 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: b9b3f391857781aa96acacef96066f2f49b4cd03cf9fce3ca4d8da2ef5ea129e + sha256: "7ee12e6dffe0fc8e755179d6d91b3b34f5924223fc104d85572ef9180d73d172" url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.2.5" vector_math: dependency: transitive description: @@ -1324,5 +1324,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.11.3 <4.0.0" - flutter: ">=3.38.4" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/pubspec.yaml b/pubspec.yaml index b6af5c7..44eed8d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: flux description: "Gestione attività negozio di telefonia" publish_to: 'none' -version: 1.1.15+33 +version: 1.1.17+35 environment: sdk: ^3.11.3