diff --git a/lib/features/master_data/providers/blocs/provider_cubit.dart b/lib/features/master_data/providers/blocs/provider_cubit.dart index a51ff6d..6d1c3fd 100644 --- a/lib/features/master_data/providers/blocs/provider_cubit.dart +++ b/lib/features/master_data/providers/blocs/provider_cubit.dart @@ -105,14 +105,45 @@ class ProvidersCubit extends Cubit { } // Salvataggio/Update anagrafica (nuovo o modifica) - Future saveProvider(ProviderModel provider) async { + Future saveProvider( + ProviderModel provider, + List selectedStoreIds, + ) async { + emit(state.copyWith(isLoading: true)); + // Assicuriamoci di settare la companyId prima di salvare + provider = provider.copyWith(companyId: _sessionBloc.state.company!.id); + try { + // 1. Salviamo l'anagrafica (upsert) + // Se è un nuovo provider, l'ID potrebbe essere generato qui dal DB + // Quindi carichiamo il risultato del salvataggio per avere l'ID + final response = await _repository.saveProvider(provider); + + // Assumiamo che il saveProvider restituisca l'oggetto salvato con l'ID + final pId = provider.id ?? response.id; + + // 2. Sincronizziamo i negozi + await _repository.syncProviderStores(pId!, selectedStoreIds); + + // 3. Ricarichiamo tutto + await loadProviders(null); + } catch (e) { + emit(state.copyWith(isLoading: false, errorMessage: e.toString())); + } + } + + Future saveProviderWithStores( + ProviderModel provider, + List storeIds, + ) async { emit(state.copyWith(isLoading: true)); try { - final providerWithCompanyId = provider.copyWith( - companyId: _sessionBloc.state.company!.id, - ); - await _repository.saveProvider(providerWithCompanyId); - // Ricarichiamo la lista per vedere le modifiche + // 1. Salva l'anagrafica provider + await _repository.saveProvider(provider); + + // 2. Sincronizza i negozi (la via più semplice è cancellare e reinserire + // o fare un confronto tra i presenti e i nuovi) + await _repository.syncProviderStores(provider.id!, storeIds); + await loadProviders(null); } catch (e) { emit(state.copyWith(isLoading: false, errorMessage: e.toString())); diff --git a/lib/features/master_data/providers/data/provider_repository.dart b/lib/features/master_data/providers/data/provider_repository.dart index c155133..3f21fcf 100644 --- a/lib/features/master_data/providers/data/provider_repository.dart +++ b/lib/features/master_data/providers/data/provider_repository.dart @@ -102,7 +102,43 @@ class ProviderRepository { } // Salva o aggiorna l'anagrafica del Provider - Future saveProvider(ProviderModel provider) async { - await _supabase.from('provider').upsert(provider.toMap()); + Future saveProvider(ProviderModel provider) async { + try { + // .select().single() è fondamentale per farsi restituire + // l'oggetto appena creato/aggiornato con l'ID + final response = await _supabase + .from('provider') + .upsert(provider.toMap()) + .select() + .single(); + + return ProviderModel.fromMap(response); // <--- DEVE ESSERCI IL RETURN + } catch (e) { + rethrow; // <--- Rilancia l'errore al Cubit, non ritornare null! + } + } + + Future syncProviderStores( + String providerId, + List storeIds, + ) async { + try { + // 1. Eliminiamo tutte le associazioni correnti per questo provider + await _supabase + .from('providers_in_stores') + .delete() + .eq('provider_id', providerId); + + // 2. Se ci sono nuovi store da associare, li inseriamo + if (storeIds.isNotEmpty) { + final inserts = storeIds + .map((sId) => {'provider_id': providerId, 'store_id': sId}) + .toList(); + + await _supabase.from('providers_in_stores').insert(inserts); + } + } catch (e) { + throw Exception('Errore durante la sincronizzazione store: $e'); + } } } diff --git a/lib/features/master_data/providers/ui/provider_form_sheet.dart b/lib/features/master_data/providers/ui/provider_form_sheet.dart index 35a41b7..1da2781 100644 --- a/lib/features/master_data/providers/ui/provider_form_sheet.dart +++ b/lib/features/master_data/providers/ui/provider_form_sheet.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/features/master_data/providers/blocs/provider_cubit.dart'; import 'package:flux/features/master_data/providers/models/provider_model.dart'; +import 'package:flux/features/master_data/store/bloc/store_cubit.dart'; class ProviderFormSheet extends StatefulWidget { final ProviderModel? initialProvider; @@ -21,6 +22,8 @@ class _ProviderFormSheetState extends State { late bool _intrattenimento; late bool _altro; late bool _isActive; + final List _tempSelectedStoreIds = + []; // Per gestire la selezione temporanea dei negozi @override void initState() { @@ -43,8 +46,10 @@ class _ProviderFormSheetState extends State { } void _save() { - if (_nameController.text.trim().isEmpty) return; - + if (_nameController.text.trim().isEmpty) { + return; + } + final cubit = context.read(); final provider = ProviderModel( id: widget.initialProvider?.id, // Se nullo, Supabase farà insert nome: _nameController.text.trim(), @@ -58,8 +63,7 @@ class _ProviderFormSheetState extends State { companyId: '', // Verrà ignorato dal toMap e gestito dal Cubit/SessionBloc se hai messo la logica lì ); - - context.read().saveProvider(provider); + cubit.saveProvider(provider, _tempSelectedStoreIds); Navigator.pop(context); } @@ -87,6 +91,7 @@ class _ProviderFormSheetState extends State { const SizedBox(height: 16), TextField( controller: _nameController, + keyboardType: TextInputType.name, decoration: const InputDecoration( labelText: "Nome Gestore/Brand", border: OutlineInputBorder(), @@ -133,6 +138,37 @@ class _ProviderFormSheetState extends State { _isActive, (v) => setState(() => _isActive = v), ), + const Divider(), + const Text( + "Abilita nei Negozi", + style: TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 8), + // Qui usiamo un BlocBuilder per prendere la lista di tutti i negozi della company + BlocBuilder( + builder: (context, storeState) { + return Column( + children: storeState.stores.map((store) { + final isAssociated = _tempSelectedStoreIds.contains( + store.id, + ); + return CheckboxListTile( + title: Text(store.nome), + value: isAssociated, + onChanged: (val) { + setState(() { + if (val == true) { + _tempSelectedStoreIds.add(store.id!); + } else { + _tempSelectedStoreIds.remove(store.id); + } + }); + }, + ); + }).toList(), + ); + }, + ), const SizedBox(height: 24), ElevatedButton( style: ElevatedButton.styleFrom( diff --git a/lib/features/master_data/providers/ui/providers_master_data_screen.dart b/lib/features/master_data/providers/ui/providers_master_data_screen.dart index 39fdb9a..d88ba22 100644 --- a/lib/features/master_data/providers/ui/providers_master_data_screen.dart +++ b/lib/features/master_data/providers/ui/providers_master_data_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/features/master_data/providers/blocs/provider_cubit.dart'; import 'package:flux/features/master_data/providers/models/provider_model.dart'; import 'package:flux/features/master_data/providers/ui/provider_form_sheet.dart'; +import 'package:flux/features/master_data/store/bloc/store_cubit.dart'; class ProvidersMasterDataScreen extends StatefulWidget { const ProvidersMasterDataScreen({super.key}); @@ -133,7 +134,6 @@ class _ProvidersMasterDataScreenState extends State { ); }, ), - _buildProviderBadges(provider), ], ); } @@ -162,12 +162,20 @@ class _ProvidersMasterDataScreenState extends State { // DIALOG PER INSERIMENTO/MODIFICA void _showProviderForm(BuildContext context, ProviderModel? provider) { + final providersCubit = context.read(); + final storeCubit = context.read(); // Implementeremo qui il form con i vari SwitchListTile // Per ora facciamo un segnaposto o passiamo a scriverlo seriamente showModalBottomSheet( context: context, isScrollControlled: true, - builder: (_) => ProviderFormSheet(initialProvider: provider), + builder: (modalContext) => MultiBlocProvider( + providers: [ + BlocProvider.value(value: providersCubit), + BlocProvider.value(value: storeCubit), + ], + child: ProviderFormSheet(initialProvider: provider), + ), ); } }