default provider
Some checks failed
Build and Release FLUX (Multi-Platform) / build-android (push) Successful in 1m59s
Build and Release FLUX (Multi-Platform) / build-web (push) Successful in 1m22s
Build and Release FLUX (Multi-Platform) / build-windows (push) Has been cancelled

This commit is contained in:
2026-06-02 13:12:21 +02:00
parent a51ac8fe7f
commit 3210b4fcfa
12 changed files with 435 additions and 170 deletions

View File

@@ -247,4 +247,13 @@ class SessionCubit extends Cubit<SessionState> {
void setIsSingleUserMode(bool isSingleUser) {
emit(state.copyWith(isSingleUserMode: isSingleUser));
}
void updateCurrentStoreLocally(StoreModel updatedStore) {
// Verifichiamo che l'utente stia effettivamente lavorando nel negozio appena modificato
if (state.currentStore != null &&
state.currentStore!.id == updatedStore.id) {
// Emettiamo il nuovo stato sovrascrivendo solo il negozio corrente
emit(state.copyWith(currentStore: updatedStore));
}
}
}

View File

@@ -0,0 +1,28 @@
import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/master_data/providers/models/provider_role.dart';
extension ProviderCompatibility on ProviderModel {
bool supportsOperation(String operationType) {
if (operationType == 'Altro') return true;
switch (operationType) {
case 'AL' || 'MNP':
return roles.contains(ProviderRole.mobile);
case 'NIP' || 'FWA':
return roles.contains(ProviderRole.landline);
case 'UNICA':
return roles.contains(ProviderRole.landline) ||
roles.contains(ProviderRole.mobile);
case 'Energy':
return roles.contains(ProviderRole.energy);
case 'Fin':
return roles.contains(ProviderRole.financing);
case 'Entertainment':
return roles.contains(ProviderRole.entertainment);
case 'TELEPASS':
return roles.contains(ProviderRole.telepass);
default:
return true;
}
}
}

View File

@@ -17,14 +17,18 @@ class StoreCubit extends Cubit<StoreState> {
StoreCubit() : super(const StoreState(stores: []));
Future<void> createStore(final StoreModel store) async {
Future<void> saveStore(final StoreModel store) async {
emit(state.copyWith(status: StoreStatus.loading));
try {
await _repository.createStore(store);
emit(state.copyWith(status: StoreStatus.success));
final savedStore = await _repository.saveStore(store);
emit(state.copyWith(status: StoreStatus.success, savedStore: savedStore));
} catch (e) {
emit(
state.copyWith(status: StoreStatus.failure, errorMessage: e.toString()),
state.copyWith(
status: StoreStatus.failure,
errorMessage: e.toString(),
savedStore: null,
),
);
}
}
@@ -70,6 +74,7 @@ class StoreCubit extends Cubit<StoreState> {
state.copyWith(
status: StoreStatus.failure,
errorMessage: "Errore nel salvataggio dei provider: $e",
savedStore: null,
),
);
}
@@ -90,6 +95,7 @@ class StoreCubit extends Cubit<StoreState> {
state.copyWith(
status: StoreStatus.failure,
errorMessage: "Errore nel salvataggio dello staff: $e",
savedStore: null,
),
);
}
@@ -110,6 +116,7 @@ class StoreCubit extends Cubit<StoreState> {
state.copyWith(
status: StoreStatus.failure,
errorMessage: "Errore nell'associazione: $e",
savedStore: null,
),
);
}
@@ -130,6 +137,7 @@ class StoreCubit extends Cubit<StoreState> {
state.copyWith(
status: StoreStatus.failure,
errorMessage: "Errore nella rimozione: $e",
savedStore: null,
),
);
}
@@ -142,7 +150,11 @@ class StoreCubit extends Cubit<StoreState> {
loadStores();
} catch (e) {
emit(
state.copyWith(status: StoreStatus.failure, errorMessage: e.toString()),
state.copyWith(
status: StoreStatus.failure,
errorMessage: e.toString(),
savedStore: null,
),
);
}
}
@@ -157,6 +169,7 @@ class StoreCubit extends Cubit<StoreState> {
state.copyWith(
status: StoreStatus.failure,
errorMessage: "Errore nella rimozione: $e",
savedStore: null,
),
);
}

View File

@@ -7,6 +7,8 @@ class StoreState extends Equatable {
final StoreModel? store;
final String? errorMessage;
final List<StoreModel> stores;
final StoreModel?
savedStore; // Per tenere traccia del negozio appena salvato (utile per aggiornare la sessione)
final Map<String, List<StaffMemberModel>> staffByStore;
const StoreState({
@@ -14,6 +16,7 @@ class StoreState extends Equatable {
this.store,
this.errorMessage,
required this.stores,
this.savedStore,
this.staffByStore = const {},
});
@@ -22,6 +25,7 @@ class StoreState extends Equatable {
StoreModel? store,
String? errorMessage,
List<StoreModel>? stores,
StoreModel? savedStore,
Map<String, List<StaffMemberModel>>? staffByStore,
}) {
return StoreState(
@@ -29,6 +33,7 @@ class StoreState extends Equatable {
store: store ?? this.store,
errorMessage: errorMessage ?? this.errorMessage,
stores: stores ?? this.stores,
savedStore: savedStore ?? this.savedStore,
staffByStore: staffByStore ?? this.staffByStore,
);
}
@@ -39,6 +44,7 @@ class StoreState extends Equatable {
store,
errorMessage,
stores,
savedStore,
staffByStore,
];
}

View File

@@ -9,7 +9,7 @@ class StoreRepository {
final SupabaseClient _supabase = GetIt.I.get<SupabaseClient>();
/// Crea un nuovo negozio associato alla compagnia dell'utente
Future<void> createStore(StoreModel store) async {
/* Future<void> createStore(StoreModel store) async {
try {
await _supabase.from(Tables.stores).insert(store.toMap());
} on PostgrestException catch (e) {
@@ -18,7 +18,7 @@ class StoreRepository {
} catch (e) {
throw 'Errore imprevisto durante la creazione del negozio: $e';
}
}
} */
Future<StoreModel> saveStore(StoreModel store) async {
try {

View File

@@ -16,6 +16,7 @@ class StoreModel extends Equatable {
final List<ProviderModel> associatedProviders; // Provider associati
final List<StaffMemberModel>
associatedStaffMembers; // Membri dello staff associati
final String? defaultProviderId; // ID del provider di default (opzionale)
const StoreModel({
this.id,
@@ -30,6 +31,7 @@ class StoreModel extends Equatable {
required this.province,
this.associatedProviders = const [],
this.associatedStaffMembers = const [],
this.defaultProviderId,
});
// Fondamentale per Equatable: definisce quali proprietà determinano l'uguaglianza
@@ -47,6 +49,7 @@ class StoreModel extends Equatable {
province,
associatedProviders,
associatedStaffMembers,
defaultProviderId,
];
// Il mitico copyWith per creare nuove istanze modificando solo ciò che serve
@@ -63,6 +66,7 @@ class StoreModel extends Equatable {
String? province,
List<ProviderModel>? associatedProviders,
List<StaffMemberModel>? associatedStaffMembers,
String? Function()? defaultProviderId,
}) {
return StoreModel(
id: id ?? this.id,
@@ -78,6 +82,9 @@ class StoreModel extends Equatable {
associatedProviders: associatedProviders ?? this.associatedProviders,
associatedStaffMembers:
associatedStaffMembers ?? this.associatedStaffMembers,
defaultProviderId: defaultProviderId != null
? defaultProviderId()
: this.defaultProviderId,
);
}
@@ -131,6 +138,7 @@ class StoreModel extends Equatable {
province: map['province'],
associatedProviders: providers,
associatedStaffMembers: staffMembers,
defaultProviderId: map['default_provider_id'] as String?,
);
}
@@ -147,6 +155,7 @@ class StoreModel extends Equatable {
'zip_code': zipCode,
'city': city,
'province': province,
'default_provider_id': defaultProviderId,
};
}
}

View File

@@ -76,7 +76,7 @@ class _CreateStoreScreenState extends State<CreateStoreScreen> {
province: _provinciaController.text.trim().toUpperCase(),
);
context.read<StoreCubit>().createStore(store);
context.read<StoreCubit>().saveStore(store);
}
}

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/widgets/flux_text_field.dart';
import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart';
import 'package:flux/features/master_data/store/bloc/store_cubit.dart';
import 'package:flux/features/master_data/store/models/store_model.dart';
@@ -19,6 +20,8 @@ class _StoreFormState extends State<StoreForm> {
final capController = TextEditingController();
final comuneController = TextEditingController();
final provinciaController = TextEditingController();
String?
_selectedDefaultProviderId; // Per tenere traccia del provider di default selezionato
@override
void initState() {
@@ -29,129 +32,241 @@ class _StoreFormState extends State<StoreForm> {
capController.text = widget.store!.zipCode;
comuneController.text = widget.store!.city;
provinciaController.text = widget.store!.province;
_selectedDefaultProviderId = widget.store!.defaultProviderId;
}
context.read<ProviderListCubit>().loadProviders(
widget.store!.id!,
); // Carichiamo i gestori per la dropdown
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
),
padding: EdgeInsets.only(
top: 24,
left: 24,
right: 24,
bottom: MediaQuery.of(context).viewInsets.bottom + 24,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.store == null ? "Nuovo Punto Vendita" : "Modifica Negozio",
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
return BlocListener<StoreCubit, StoreState>(
listener: (context, state) {
if (state.status == StoreStatus.success) {
// 1. Diciamo alla schermata di ricaricare la lista generale dei negozi (se serve)
context.read<StoreCubit>().loadStores();
// 🥷 2. IL TOCCO FINALE: Aggiorniamo la sessione globale se stiamo modificando il negozio attivo!
if (state.savedStore != null) {
context.read<SessionCubit>().updateCurrentStoreLocally(
state.savedStore!,
);
}
// 3. Chiudiamo il form
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Negozio aggiornato con successo!',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.green,
),
const SizedBox(height: 24),
);
Navigator.pop(context);
}
// --- DATI PRINCIPALI ---
FluxTextField(
controller: nomeController,
label: "Nome Negozio (es. Flux Milano)",
icon: Icons.storefront_rounded,
keyboardType: TextInputType.name,
if (state.status == StoreStatus.failure) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage ?? 'Errore di salvataggio'),
backgroundColor: Colors.red,
),
const SizedBox(height: 16),
FluxTextField(
controller: indirizzoController,
label: "Indirizzo",
icon: Icons.map_outlined,
keyboardType: TextInputType.streetAddress,
),
const SizedBox(height: 16),
// --- CAP, COMUNE, PROVINCIA (In riga) ---
Row(
children: [
Expanded(
flex: 2,
child: FluxTextField(
controller: capController,
label: "CAP",
icon: Icons.post_add_rounded,
keyboardType: TextInputType.number,
maxLength: 5,
),
),
const SizedBox(width: 8),
Expanded(
flex: 4,
child: FluxTextField(
controller: comuneController,
label: "Comune",
icon: Icons.location_city_rounded,
keyboardType: TextInputType.name,
),
),
const SizedBox(width: 8),
Expanded(
flex: 2,
child: FluxTextField(
controller: provinciaController,
label: "Prov",
icon: Icons.explore_outlined,
keyboardType: TextInputType.name,
onChanged: (value) => value.toUpperCase(),
maxLength: 2,
),
),
],
),
const SizedBox(height: 32),
// --- TASTO SALVA ---
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () {
if (nomeController.text.isEmpty) return;
final storeData = StoreModel(
id: widget
.store
?.id, // Se nullo, Supabase ne crea uno nuovo
name: nomeController.text,
address: indirizzoController.text,
zipCode: capController.text,
city: comuneController.text,
province: provinciaController.text,
companyId: context
.read<SessionCubit>()
.state
.company!
.id!, // Recuperiamo la companyId
isActive: widget.store?.isActive ?? true,
isPaid: widget.store?.isPaid ?? false,
paymentExpiration: widget.store?.paymentExpiration,
);
// Chiamata al Bloc per il salvataggio
context.read<StoreCubit>().createStore(storeData);
Navigator.pop(context);
},
child: Text(
widget.store == null ? "CREA NEGOZIO" : "AGGIORNA DATI",
);
}
},
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
),
padding: EdgeInsets.only(
top: 24,
left: 24,
right: 24,
bottom: MediaQuery.of(context).viewInsets.bottom + 24,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.store == null
? "Nuovo Punto Vendita"
: "Modifica Negozio",
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
const SizedBox(height: 24),
// --- DATI PRINCIPALI ---
FluxTextField(
controller: nomeController,
label: "Nome Negozio (es. Flux Milano)",
icon: Icons.storefront_rounded,
keyboardType: TextInputType.name,
),
const SizedBox(height: 16),
FluxTextField(
controller: indirizzoController,
label: "Indirizzo",
icon: Icons.map_outlined,
keyboardType: TextInputType.streetAddress,
),
const SizedBox(height: 16),
// --- CAP, COMUNE, PROVINCIA (In riga) ---
Row(
children: [
Expanded(
flex: 2,
child: FluxTextField(
controller: capController,
label: "CAP",
icon: Icons.post_add_rounded,
keyboardType: TextInputType.number,
maxLength: 5,
),
),
const SizedBox(width: 8),
Expanded(
flex: 4,
child: FluxTextField(
controller: comuneController,
label: "Comune",
icon: Icons.location_city_rounded,
keyboardType: TextInputType.name,
),
),
const SizedBox(width: 8),
Expanded(
flex: 2,
child: FluxTextField(
controller: provinciaController,
label: "Prov",
icon: Icons.explore_outlined,
keyboardType: TextInputType.name,
onChanged: (value) => value.toUpperCase(),
maxLength: 2,
),
),
],
),
const SizedBox(height: 16),
// --- GESTORI ---
_defaultProviderDropdown(),
const SizedBox(height: 32),
// --- TASTO SALVA ---
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () {
if (nomeController.text.isEmpty) return;
final storeData = StoreModel(
id: widget
.store
?.id, // Se nullo, Supabase ne crea uno nuovo
name: nomeController.text,
address: indirizzoController.text,
zipCode: capController.text,
city: comuneController.text,
province: provinciaController.text,
companyId: context
.read<SessionCubit>()
.state
.company!
.id!, // Recuperiamo la companyId
isActive: widget.store?.isActive ?? true,
isPaid: widget.store?.isPaid ?? false,
paymentExpiration: widget.store?.paymentExpiration,
defaultProviderId: _selectedDefaultProviderId,
);
// Chiamata al Bloc per il salvataggio
context.read<StoreCubit>().saveStore(storeData);
},
child: Text(
widget.store == null ? "CREA NEGOZIO" : "AGGIORNA DATI",
),
),
),
],
),
),
),
);
}
Widget _defaultProviderDropdown() {
return BlocBuilder<ProviderListCubit, ProviderListState>(
builder: (context, state) {
if (state.status == ProviderListStatus.loading) {
return const Center(child: CircularProgressIndicator());
}
final activeProviders = state.providers
.where((p) => p.isActive)
.toList();
// 🥷 SCENARIO ONBOARDING: La lista dei gestori è vuota
if (activeProviders.isEmpty) {
return TextFormField(
enabled: false, // Disabilitiamo il campo
decoration: InputDecoration(
labelText: 'Gestore di Default',
hintText: 'Configura prima i gestori nell\'hub anagrafiche',
hintStyle: TextStyle(color: Colors.grey[500], fontSize: 13),
prefixIcon: const Icon(Icons.star_border, color: Colors.grey),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey[300]!),
),
fillColor: Colors.grey[50],
filled: true,
),
);
}
// SCENARIO STANDARD: Ci sono gestori censiti, mostriamo la dropdown
return DropdownButtonFormField<String?>(
initialValue: _selectedDefaultProviderId,
decoration: InputDecoration(
labelText: 'Gestore di Default (Opzionale)',
hintText: 'Seleziona se questo è un negozio monomarca',
prefixIcon: const Icon(Icons.star_border, color: Colors.amber),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
),
items: [
const DropdownMenuItem<String?>(
value: null,
child: Text(
'Nessun gestore (Multi-brand)',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
...activeProviders.map((p) {
return DropdownMenuItem<String?>(
value: p.id,
child: Text(p.name),
);
}),
],
onChanged: (val) {
setState(() {
_selectedDefaultProviderId = val;
});
},
);
},
);
}
}

View File

@@ -2,6 +2,8 @@ import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/customers/models/customer_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model_extensions.dart';
import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
import 'package:flux/features/operations/data/operations_repository.dart';
import 'package:flux/features/operations/models/operation_model.dart';
@@ -278,27 +280,126 @@ class OperationFormCubit extends Cubit<OperationFormState> {
// --- UTILS ---
void setTypeWithSmartDefault(String type) {
void updateOperationType(
String newType, {
required List<ProviderModel> allProviders,
String? defaultProviderId,
}) {
// 1. Aggiorniamo il tipo nel modello in canna
// (Presumo tu abbia un metodo copyWith o simile)
final updatedOp = state.operation.copyWith(type: newType, subtype: '');
// 2. Prepariamoci ad auto-selezionare il provider
String? newProviderId = updatedOp.providerId;
String? newProviderName = updatedOp.providerDisplayName;
// 3. LA LOGICA DI DEFAULT
if (defaultProviderId != null) {
// Troviamo il provider di default nella lista
final defaultProvider = allProviders
.where((p) => p.id == defaultProviderId)
.firstOrNull;
if (defaultProvider != null) {
// Usiamo l'extension appena creata!
if (defaultProvider.supportsOperation(newType)) {
newProviderId = defaultProvider.id;
newProviderName = defaultProvider.name;
} else {
// Se cambi tipo (es. da Mobile a Luce) e il default non lo supporta, sbianchiamo
newProviderId = null;
newProviderName = null;
}
}
}
// Emettiamo il nuovo stato
emit(
state.copyWith(
operation: updatedOp.copyWith(
providerId: newProviderId,
providerDisplayName: newProviderName,
),
),
);
}
void setTypeWithSmartDefaults({
required String newType,
required List<ProviderModel> allProviders,
String? defaultProviderId,
}) {
final currentOp = state.operation;
// -----------------------------------------
// 1. SMART DATES: Calcolo Scadenze Default
// -----------------------------------------
DateTime? defaultDate;
final now = DateTime.now();
if (type == 'Energy') {
if (newType == 'Energy') {
defaultDate = DateTime(now.year, now.month + 24, now.day);
}
if (type == 'Fin') {
if (newType == 'Fin') {
defaultDate = DateTime(now.year, now.month + 30, now.day);
}
if (type == 'Entertainment') {
if (newType == 'Entertainment') {
defaultDate = DateTime(now.year, now.month + 12, now.day);
}
updateFields(
type: type,
expirationDate: defaultDate,
clearProvider: true,
clearSubtype: true,
clearModel: true,
clearQuantity: true,
// -----------------------------------------
// 2. SMART PROVIDER: Filtro e Auto-Selezione
// -----------------------------------------
String? newProviderId = currentOp.providerId;
String? newProviderName = currentOp.providerDisplayName;
// A) Il provider attuale è ancora compatibile col nuovo tipo scelto?
if (newProviderId != null && newProviderId.isNotEmpty) {
final currentProvider = allProviders
.where((p) => p.id == newProviderId)
.firstOrNull;
if (currentProvider == null ||
!currentProvider.supportsOperation(newType)) {
// Non è più compatibile (es. da TIM fisso passo a Energy). Lo sbianchiamo!
newProviderId = null;
newProviderName = null;
}
}
// B) Se non c'è un provider selezionato, proviamo ad auto-inserire quello di default del negozio
if ((newProviderId == null || newProviderId.isEmpty) &&
defaultProviderId != null) {
final defaultProvider = allProviders
.where((p) => p.id == defaultProviderId)
.firstOrNull;
// Controlliamo che il default del negozio supporti questa specifica operazione
if (defaultProvider != null &&
defaultProvider.supportsOperation(newType)) {
newProviderId = defaultProvider.id;
newProviderName = defaultProvider.name;
}
}
// -----------------------------------------
// 3. EMISSIONE DELLO STATO PULITO
// -----------------------------------------
emit(
state.copyWith(
operation: currentOp.copyWith(
type: newType,
subtype:
'', // Resettiamo il sottotipo per evitare incongruenze (es. passo da Luce a DAZN)
expirationDate:
defaultDate, // Impostiamo la scadenza di default se calcolata
providerId: newProviderId,
providerDisplayName: newProviderName,
modelId: null,
modelDisplayName: null,
),
),
);
}
}

View File

@@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/widgets/shared_forms/attachments_section.dart';
import 'package:flux/features/attachments/blocs/attachments_bloc.dart';
import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart';
import 'package:flux/features/operations/blocs/operation_form_cubit.dart';
import 'package:flux/features/operations/models/operation_model.dart';
import 'package:flux/core/widgets/shared_forms/customer_section.dart';
@@ -527,8 +529,24 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
selected: state.operation.type == type,
onSelected: (selected) {
if (selected) {
context.read<OperationFormCubit>().setTypeWithSmartDefault(
type,
// 1. Recuperiamo i provider caricati in memoria
final allProviders = context
.read<ProviderListCubit>()
.state
.providers;
// 2. Recuperiamo il provider di default del negozio dalla sessione
final defaultProviderId = context
.read<SessionCubit>()
.state
.currentStore
?.defaultProviderId;
// 3. Spariamo tutto nel metodo "tuttofare"
context.read<OperationFormCubit>().setTypeWithSmartDefaults(
newType: type,
allProviders: allProviders,
defaultProviderId: defaultProviderId,
);
}
},

View File

@@ -2,8 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/widgets/shared_forms/model_section.dart';
import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart';
import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/master_data/providers/models/provider_role.dart';
import 'package:flux/features/master_data/providers/models/provider_model_extensions.dart';
import 'package:flux/features/operations/blocs/operation_form_cubit.dart';
import 'package:flux/features/operations/models/operation_model.dart';
@@ -23,34 +22,6 @@ class OperationDetailsSection extends StatelessWidget {
required this.durationQuickPicks,
});
bool _doesProviderMatchOperationType(
ProviderModel provider,
String operationType,
) {
if (operationType == 'Altro') return true;
// Controlliamo che il fornitore abbia il ruolo specifico nel suo array
switch (operationType) {
case 'AL' || 'MNP':
return provider.roles.contains(ProviderRole.mobile);
case 'NIP' || 'FWA':
return provider.roles.contains(ProviderRole.landline);
case 'UNICA':
return provider.roles.contains(ProviderRole.landline) ||
provider.roles.contains(ProviderRole.mobile);
case 'Energy':
return provider.roles.contains(ProviderRole.energy);
case 'Fin':
return provider.roles.contains(ProviderRole.financing);
case 'Entertainment':
return provider.roles.contains(ProviderRole.entertainment);
case 'TELEPASS':
return provider.roles.contains(ProviderRole.telepass);
default:
return true;
}
}
void _showProviderModal(BuildContext context, String operationType) {
final OperationFormCubit cubit = context.read<OperationFormCubit>();
showModalBottomSheet(
@@ -92,14 +63,9 @@ class OperationDetailsSection extends StatelessWidget {
return const Center(child: CircularProgressIndicator());
}
// Prendiamo i provider e li filtriamo per ruolo e per stato attivo
// 🥷 IL TOCCO DEL NINJA: Filtriamo usando direttamente l'Extension sul Modello!
final filteredProviders = state.providers.where((p) {
final isMatch = _doesProviderMatchOperationType(
p,
operationType,
);
return isMatch &&
p.isActive; // Mostriamo solo quelli attivi!
return p.supportsOperation(operationType) && p.isActive;
}).toList();
if (filteredProviders.isEmpty) {