providers #3
@@ -105,14 +105,45 @@ class ProvidersCubit extends Cubit<ProvidersState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Salvataggio/Update anagrafica (nuovo o modifica)
|
// Salvataggio/Update anagrafica (nuovo o modifica)
|
||||||
Future<void> saveProvider(ProviderModel provider) async {
|
Future<void> saveProvider(
|
||||||
|
ProviderModel provider,
|
||||||
|
List<String> 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<void> saveProviderWithStores(
|
||||||
|
ProviderModel provider,
|
||||||
|
List<String> storeIds,
|
||||||
|
) async {
|
||||||
emit(state.copyWith(isLoading: true));
|
emit(state.copyWith(isLoading: true));
|
||||||
try {
|
try {
|
||||||
final providerWithCompanyId = provider.copyWith(
|
// 1. Salva l'anagrafica provider
|
||||||
companyId: _sessionBloc.state.company!.id,
|
await _repository.saveProvider(provider);
|
||||||
);
|
|
||||||
await _repository.saveProvider(providerWithCompanyId);
|
// 2. Sincronizza i negozi (la via più semplice è cancellare e reinserire
|
||||||
// Ricarichiamo la lista per vedere le modifiche
|
// o fare un confronto tra i presenti e i nuovi)
|
||||||
|
await _repository.syncProviderStores(provider.id!, storeIds);
|
||||||
|
|
||||||
await loadProviders(null);
|
await loadProviders(null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
|
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
|
||||||
|
|||||||
@@ -102,7 +102,43 @@ class ProviderRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Salva o aggiorna l'anagrafica del Provider
|
// Salva o aggiorna l'anagrafica del Provider
|
||||||
Future<void> saveProvider(ProviderModel provider) async {
|
Future<ProviderModel> saveProvider(ProviderModel provider) async {
|
||||||
await _supabase.from('provider').upsert(provider.toMap());
|
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<void> syncProviderStores(
|
||||||
|
String providerId,
|
||||||
|
List<String> 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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.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/blocs/provider_cubit.dart';
|
||||||
import 'package:flux/features/master_data/providers/models/provider_model.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 {
|
class ProviderFormSheet extends StatefulWidget {
|
||||||
final ProviderModel? initialProvider;
|
final ProviderModel? initialProvider;
|
||||||
@@ -21,6 +22,8 @@ class _ProviderFormSheetState extends State<ProviderFormSheet> {
|
|||||||
late bool _intrattenimento;
|
late bool _intrattenimento;
|
||||||
late bool _altro;
|
late bool _altro;
|
||||||
late bool _isActive;
|
late bool _isActive;
|
||||||
|
final List<String> _tempSelectedStoreIds =
|
||||||
|
[]; // Per gestire la selezione temporanea dei negozi
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -43,8 +46,10 @@ class _ProviderFormSheetState extends State<ProviderFormSheet> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _save() {
|
void _save() {
|
||||||
if (_nameController.text.trim().isEmpty) return;
|
if (_nameController.text.trim().isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final cubit = context.read<ProvidersCubit>();
|
||||||
final provider = ProviderModel(
|
final provider = ProviderModel(
|
||||||
id: widget.initialProvider?.id, // Se nullo, Supabase farà insert
|
id: widget.initialProvider?.id, // Se nullo, Supabase farà insert
|
||||||
nome: _nameController.text.trim(),
|
nome: _nameController.text.trim(),
|
||||||
@@ -58,8 +63,7 @@ class _ProviderFormSheetState extends State<ProviderFormSheet> {
|
|||||||
companyId:
|
companyId:
|
||||||
'', // Verrà ignorato dal toMap e gestito dal Cubit/SessionBloc se hai messo la logica lì
|
'', // Verrà ignorato dal toMap e gestito dal Cubit/SessionBloc se hai messo la logica lì
|
||||||
);
|
);
|
||||||
|
cubit.saveProvider(provider, _tempSelectedStoreIds);
|
||||||
context.read<ProvidersCubit>().saveProvider(provider);
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +91,7 @@ class _ProviderFormSheetState extends State<ProviderFormSheet> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Nome Gestore/Brand",
|
labelText: "Nome Gestore/Brand",
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
@@ -133,6 +138,37 @@ class _ProviderFormSheetState extends State<ProviderFormSheet> {
|
|||||||
_isActive,
|
_isActive,
|
||||||
(v) => setState(() => _isActive = v),
|
(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<StoreCubit, StoreState>(
|
||||||
|
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),
|
const SizedBox(height: 24),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
|
|||||||
@@ -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/blocs/provider_cubit.dart';
|
||||||
import 'package:flux/features/master_data/providers/models/provider_model.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/providers/ui/provider_form_sheet.dart';
|
||||||
|
import 'package:flux/features/master_data/store/bloc/store_cubit.dart';
|
||||||
|
|
||||||
class ProvidersMasterDataScreen extends StatefulWidget {
|
class ProvidersMasterDataScreen extends StatefulWidget {
|
||||||
const ProvidersMasterDataScreen({super.key});
|
const ProvidersMasterDataScreen({super.key});
|
||||||
@@ -133,7 +134,6 @@ class _ProvidersMasterDataScreenState extends State<ProvidersMasterDataScreen> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_buildProviderBadges(provider),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -162,12 +162,20 @@ class _ProvidersMasterDataScreenState extends State<ProvidersMasterDataScreen> {
|
|||||||
|
|
||||||
// DIALOG PER INSERIMENTO/MODIFICA
|
// DIALOG PER INSERIMENTO/MODIFICA
|
||||||
void _showProviderForm(BuildContext context, ProviderModel? provider) {
|
void _showProviderForm(BuildContext context, ProviderModel? provider) {
|
||||||
|
final providersCubit = context.read<ProvidersCubit>();
|
||||||
|
final storeCubit = context.read<StoreCubit>();
|
||||||
// Implementeremo qui il form con i vari SwitchListTile
|
// Implementeremo qui il form con i vari SwitchListTile
|
||||||
// Per ora facciamo un segnaposto o passiamo a scriverlo seriamente
|
// Per ora facciamo un segnaposto o passiamo a scriverlo seriamente
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder: (_) => ProviderFormSheet(initialProvider: provider),
|
builder: (modalContext) => MultiBlocProvider(
|
||||||
|
providers: [
|
||||||
|
BlocProvider.value(value: providersCubit),
|
||||||
|
BlocProvider.value(value: storeCubit),
|
||||||
|
],
|
||||||
|
child: ProviderFormSheet(initialProvider: provider),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user