diff --git a/lib/features/master_data/master_data_hub_content.dart b/lib/features/master_data/master_data_hub_content.dart index a55d2ac..03082d8 100644 --- a/lib/features/master_data/master_data_hub_content.dart +++ b/lib/features/master_data/master_data_hub_content.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flux/core/theme/theme.dart'; import 'package:flux/features/customers/ui/customers_content.dart'; import 'package:flux/features/master_data/products/ui/products_screen.dart'; +import 'package:flux/features/master_data/providers/ui/providers_master_data_screen.dart'; import 'package:flux/features/master_data/staff/ui/staff_screen.dart'; import 'package:flux/features/master_data/store/ui/stores_screen.dart'; @@ -38,34 +39,57 @@ class MasterDataHubContent extends StatelessWidget { mainAxisSpacing: 16, crossAxisSpacing: 16, children: [ - _HubCard( - label: 'Prodotti', + _buildHubCard( + context, + title: 'Prodotti', + subtitle: 'Anagrafica di Marche e Modelli', icon: Icons.inventory_2_outlined, color: Colors.blue, onTap: () => onOpenPage( const ProductsScreen(), ), // Apre ProductsScreen, // Indice per ProductsScreen ), - _HubCard( - label: 'Clienti', + _buildHubCard( + context, + title: 'Clienti', + subtitle: 'Anagrafica dei clienti del tuo business', icon: Icons.people_outlined, color: Colors.orange, onTap: () => onOpenPage( const CustomersContent(), ), // Indice per CustomersContent ), - _HubCard( - label: 'Commessi', + _buildHubCard( + context, + title: 'Addetti', + subtitle: 'Anagrafica del personale e dei collaboratori', icon: Icons.badge_outlined, color: Colors.teal, onTap: () => onOpenPage(const StaffScreen()), ), - _HubCard( - label: 'Negozi', + _buildHubCard( + context, + title: 'Negozi', + subtitle: 'Anagrafica punti vendita della tua azienda', icon: Icons.storefront_outlined, color: Colors.purple, onTap: () => onOpenPage(const StoresScreen()), ), + _buildHubCard( + context, + title: 'Gestione Provider', + subtitle: 'Anagrafica mandati e servizi abilitati', + icon: Icons.handshake_rounded, + color: Colors.indigo, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ProvidersMasterDataScreen(), + ), + ); + }, + ), ], ), ), @@ -75,41 +99,57 @@ class MasterDataHubContent extends StatelessWidget { } } -// Widget semplice per le card dell'hub -class _HubCard extends StatelessWidget { - final String label; - final IconData icon; - final Color color; - final VoidCallback onTap; - - const _HubCard({ - required this.label, - required this.icon, - required this.color, - required this.onTap, - }); - - @override - Widget build(BuildContext context) { - return Card( - elevation: 0, - color: context.background, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - side: BorderSide(color: context.accent.withValues(alpha: 0.1)), - ), - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(16), +Widget _buildHubCard( + BuildContext context, { + required String title, + required String subtitle, + required IconData icon, + required Color color, + required VoidCallback onTap, +}) { + return Card( + clipBehavior: Clip.antiAlias, + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), // Un pelo più arrotondato + child: InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.all( + 24.0, + ), // Aumentiamo il padding per dare respiro child: Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, // CENTRA VERTICALMENTE + crossAxisAlignment: + CrossAxisAlignment.center, // CENTRA ORIZZONTALMENTE children: [ - Icon(icon, color: color, size: 40), - const SizedBox(height: 12), - Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), + // Icona con un leggero sfondo circolare opaco per farla risaltare + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: color.withValues(alpha: 0.1), // <--- API moderna + shape: BoxShape.circle, + ), + child: Icon(icon, size: 48, color: color), + ), + const SizedBox(height: 16), + Text( + title, + textAlign: TextAlign.center, // Centra il testo + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 8), + Text( + subtitle, + textAlign: TextAlign.center, // Centra il sottotitolo + style: TextStyle(fontSize: 13, color: Colors.grey.shade500), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), ], ), ), - ); - } + ), + ); } diff --git a/lib/features/master_data/providers/blocs/provider_cubit.dart b/lib/features/master_data/providers/blocs/provider_cubit.dart index 07ea2d7..6d1c3fd 100644 --- a/lib/features/master_data/providers/blocs/provider_cubit.dart +++ b/lib/features/master_data/providers/blocs/provider_cubit.dart @@ -1,6 +1,8 @@ import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flux/core/blocs/session/session_bloc.dart'; import 'package:flux/features/master_data/providers/data/provider_repository.dart'; +import 'package:flux/features/master_data/store/models/store_model.dart'; import 'package:get_it/get_it.dart'; import '../models/provider_model.dart'; @@ -43,18 +45,21 @@ class ProvidersState extends Equatable { class ProvidersCubit extends Cubit { final ProviderRepository _repository = GetIt.I(); + final SessionBloc _sessionBloc; - ProvidersCubit() : super(const ProvidersState()); + ProvidersCubit(this._sessionBloc) : super(const ProvidersState()); // Carica i provider della company e quelli associati a uno store specifico - Future loadProviders(String companyId, String? storeId) async { + Future loadProviders(StoreModel? store) async { emit(state.copyWith(isLoading: true)); try { - final all = await _repository.fetchAllCompanyProviders(companyId); + final all = await _repository.fetchAllCompanyProviders( + _sessionBloc.state.company!.id, + ); List associated = []; - if (storeId != null) { - associated = await _repository.fetchAssociatedProviderIds(storeId); + if (store != null) { + associated = await _repository.fetchAssociatedProviderIds(store.id!); } emit( @@ -100,12 +105,46 @@ 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 { + // 1. Salva l'anagrafica provider await _repository.saveProvider(provider); - // Ricarichiamo la lista per vedere le modifiche - await loadProviders(provider.companyId, null); + + // 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 46bb48a..3f21fcf 100644 --- a/lib/features/master_data/providers/data/provider_repository.dart +++ b/lib/features/master_data/providers/data/provider_repository.dart @@ -40,14 +40,29 @@ class ProviderRepository { // Recupera tutti i provider di una company (per la lista generale) Future> fetchAllCompanyProviders(String companyId) async { try { + // La magia è qui: selezioniamo tutto e chiediamo il conteggio (count) + // della tabella pivot providers_in_stores final response = await _supabase .from('provider') - .select() - .eq('company_id', companyId); + .select(''' + *, + providers_in_stores(count) + ''') + .eq('company_id', companyId) + .order('nome'); - return (response as List).map((m) => ProviderModel.fromMap(m)).toList(); + return (response as List).map((m) { + // Estraiamo il conteggio dalla struttura restituita da Supabase + // La risposta per ogni riga sarà tipo: { "id": "...", "providers_in_stores": [{"count": 5}] } + final storesList = m['providers_in_stores'] as List?; + final count = (storesList != null && storesList.isNotEmpty) + ? storesList[0]['count'] as int + : 0; + + return ProviderModel.fromMap(m).copyWith(storesCount: count); + }).toList(); } catch (e) { - throw Exception('Errore fetch provider: $e'); + throw Exception('Errore fetch all providers: $e'); } } @@ -87,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/models/provider_model.dart b/lib/features/master_data/providers/models/provider_model.dart index 55cb4f8..716bdc3 100644 --- a/lib/features/master_data/providers/models/provider_model.dart +++ b/lib/features/master_data/providers/models/provider_model.dart @@ -1,7 +1,7 @@ import 'package:equatable/equatable.dart'; class ProviderModel extends Equatable { - final String id; + final String? id; final String nome; final bool telefoniaFissa; final bool telefoniaMobile; @@ -11,9 +11,10 @@ class ProviderModel extends Equatable { final bool altro; final bool isActive; final String companyId; + final int storesCount; const ProviderModel({ - required this.id, + this.id, required this.nome, required this.telefoniaFissa, required this.telefoniaMobile, @@ -23,6 +24,7 @@ class ProviderModel extends Equatable { required this.altro, required this.isActive, required this.companyId, + this.storesCount = 0, // Numero di store associati, default a 0 }); factory ProviderModel.fromMap(Map map) { @@ -37,11 +39,16 @@ class ProviderModel extends Equatable { altro: map['altro'] ?? false, isActive: map['is_active'] ?? true, companyId: map['company_id'], + storesCount: + map['providers_in_stores'] != null && + map['providers_in_stores'].isNotEmpty + ? map['providers_in_stores'][0]['count'] as int + : 0, // Assumiamo che l'API possa restituire questo campo ); } Map toMap() { - return { + final map = { 'nome': nome, 'telefonia_fissa': telefoniaFissa, 'telefonia_mobile': telefoniaMobile, @@ -52,6 +59,12 @@ class ProviderModel extends Equatable { 'is_active': isActive, 'company_id': companyId, }; + // AGGIUNGIAMO L'ID SOLO SE NON È NULLO + // Senza questo, l'upsert non sa dove andare a parare + if (id != null) { + map['id'] = id!; + } + return map; } @override @@ -66,6 +79,7 @@ class ProviderModel extends Equatable { altro, isActive, companyId, + storesCount, ]; ProviderModel copyWith({ @@ -79,6 +93,7 @@ class ProviderModel extends Equatable { bool? altro, bool? isActive, String? companyId, + int? storesCount, }) { return ProviderModel( id: id ?? this.id, @@ -91,6 +106,7 @@ class ProviderModel extends Equatable { altro: altro ?? this.altro, isActive: isActive ?? this.isActive, companyId: companyId ?? this.companyId, + storesCount: storesCount ?? this.storesCount, ); } } diff --git a/lib/features/master_data/providers/ui/provider_form_sheet.dart b/lib/features/master_data/providers/ui/provider_form_sheet.dart new file mode 100644 index 0000000..1da2781 --- /dev/null +++ b/lib/features/master_data/providers/ui/provider_form_sheet.dart @@ -0,0 +1,195 @@ +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; + + const ProviderFormSheet({super.key, this.initialProvider}); + + @override + State createState() => _ProviderFormSheetState(); +} + +class _ProviderFormSheetState extends State { + late TextEditingController _nameController; + late bool _telefoniaFissa; + late bool _telefoniaMobile; + late bool _energia; + late bool _assicurazioni; + late bool _intrattenimento; + late bool _altro; + late bool _isActive; + final List _tempSelectedStoreIds = + []; // Per gestire la selezione temporanea dei negozi + + @override + void initState() { + super.initState(); + final p = widget.initialProvider; + _nameController = TextEditingController(text: p?.nome ?? ''); + _telefoniaFissa = p?.telefoniaFissa ?? false; + _telefoniaMobile = p?.telefoniaMobile ?? false; + _energia = p?.energia ?? false; + _assicurazioni = p?.assicurazioni ?? false; + _intrattenimento = p?.intrattenimento ?? false; + _altro = p?.altro ?? false; + _isActive = p?.isActive ?? true; + } + + @override + void dispose() { + _nameController.dispose(); + super.dispose(); + } + + void _save() { + 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(), + telefoniaFissa: _telefoniaFissa, + telefoniaMobile: _telefoniaMobile, + energia: _energia, + assicurazioni: _assicurazioni, + intrattenimento: _intrattenimento, + altro: _altro, + isActive: _isActive, + companyId: + '', // Verrà ignorato dal toMap e gestito dal Cubit/SessionBloc se hai messo la logica lì + ); + cubit.saveProvider(provider, _tempSelectedStoreIds); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of( + context, + ).viewInsets.bottom, // Gestisce la tastiera + left: 16, + right: 16, + top: 16, + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + widget.initialProvider == null + ? "Nuovo Provider" + : "Modifica Provider", + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 16), + TextField( + controller: _nameController, + keyboardType: TextInputType.name, + decoration: const InputDecoration( + labelText: "Nome Gestore/Brand", + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + const Text( + "Servizi Abilitati", + style: TextStyle(fontWeight: FontWeight.bold), + ), + _buildSwitch( + "Energia (Luce/Gas)", + _energia, + (v) => setState(() => _energia = v), + ), + _buildSwitch( + "Telefonia Fissa", + _telefoniaFissa, + (v) => setState(() => _telefoniaFissa = v), + ), + _buildSwitch( + "Telefonia Mobile", + _telefoniaMobile, + (v) => setState(() => _telefoniaMobile = v), + ), + _buildSwitch( + "Assicurazioni", + _assicurazioni, + (v) => setState(() => _assicurazioni = v), + ), + _buildSwitch( + "Intrattenimento", + _intrattenimento, + (v) => setState(() => _intrattenimento = v), + ), + _buildSwitch( + "Altro/Accessori", + _altro, + (v) => setState(() => _altro = v), + ), + const Divider(), + _buildSwitch( + "Stato Attivo", + _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( + minimumSize: const Size.fromHeight(50), + ), + onPressed: _save, + child: const Text("SALVA ANAGRAFICA"), + ), + const SizedBox(height: 24), + ], + ), + ), + ); + } + + Widget _buildSwitch(String title, bool value, Function(bool) onChanged) { + return SwitchListTile( + title: Text(title), + value: value, + onChanged: onChanged, + contentPadding: EdgeInsets.zero, + ); + } +} 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 new file mode 100644 index 0000000..d88ba22 --- /dev/null +++ b/lib/features/master_data/providers/ui/providers_master_data_screen.dart @@ -0,0 +1,181 @@ +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/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}); + + @override + State createState() => + _ProvidersMasterDataScreenState(); +} + +class _ProvidersMasterDataScreenState extends State { + @override + void initState() { + super.initState(); + // Carichiamo i provider della company (senza store specifico per ora) + context.read().loadProviders(null); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text("Anagrafica Provider")), + body: BlocBuilder( + builder: (context, state) { + if (state.isLoading && state.allProviders.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } + + if (state.allProviders.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.all(32.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Un'icona grande e stilizzata + Icon( + Icons.handshake_outlined, + size: 80, + color: Colors.indigo.withValues(alpha: 0.3), + ), + const SizedBox(height: 24), + const Text( + "Nessun Provider configurato", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 12), + const Text( + "Aggiungi i partner con cui collabori (es. Enel, WindTre, ecc.) per poter gestire i servizi e i mandati nei tuoi negozi.", + textAlign: TextAlign.center, + style: TextStyle(color: Colors.grey), + ), + const SizedBox(height: 32), + // Un bel bottone centrato per chi non vuole usare il FAB in basso + ElevatedButton.icon( + onPressed: () => _showProviderForm(context, null), + icon: const Icon(Icons.add), + label: const Text("AGGIUNGI IL PRIMO PROVIDER"), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.indigo, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + ), + ], + ), + ), + ); + } + + return ListView.separated( + itemCount: state.allProviders.length, + separatorBuilder: (context, index) => const Divider(height: 1), + itemBuilder: (context, index) { + final provider = state.allProviders[index]; + return ListTile( + leading: CircleAvatar( + backgroundColor: provider.isActive + ? Colors.green.shade100 + : Colors.grey.shade300, + child: Icon( + Icons.business, + color: provider.isActive ? Colors.green : Colors.grey, + ), + ), + title: Text( + provider.nome, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: _buildCardSubtitle( + provider, + ), // Una funzione che costruisce il sottotitolo con i badge + trailing: const Icon(Icons.edit_outlined), + onTap: () => _showProviderForm(context, provider), + ); + }, + ); + }, + ), + floatingActionButton: FloatingActionButton( + onPressed: () => _showProviderForm(context, null), + child: const Icon(Icons.add), + ), + ); + } + + Widget _buildCardSubtitle(ProviderModel provider) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildProviderBadges(provider), // I badge che abbiamo fatto prima + const SizedBox(height: 4), + BlocBuilder( + builder: (context, state) { + // Un piccolo testo che indica il numero di store associati + // Nota: Dovrai assicurarti che il Cubit carichi queste info + return Text( + "Disponibile in ${provider.storesCount} negozi", + style: TextStyle( + fontSize: 11, + color: Colors.indigo.withValues(alpha: 0.7), + ), + ); + }, + ), + ], + ); + } + + // Visualizza i servizi abilitati per quel provider nella lista + Widget _buildProviderBadges(ProviderModel p) { + return Wrap( + spacing: 4, + children: [ + if (p.telefoniaFissa || p.telefoniaMobile) + _smallTag("📞 Tel", Colors.blue), + if (p.energia) _smallTag("⚡ Energy", Colors.orange), + if (p.assicurazioni) _smallTag("🛡️ Assic", Colors.teal), + if (p.intrattenimento) _smallTag("📺 Ent", Colors.red), + if (p.altro) _smallTag("📦 Altro", Colors.grey), + ], + ); + } + + Widget _smallTag(String label, Color color) { + return Text( + label, + style: TextStyle(color: color, fontSize: 10, fontWeight: FontWeight.w600), + ); + } + + // 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: (modalContext) => MultiBlocProvider( + providers: [ + BlocProvider.value(value: providersCubit), + BlocProvider.value(value: storeCubit), + ], + child: ProviderFormSheet(initialProvider: provider), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 147acc4..e45f98b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; @@ -14,6 +12,8 @@ import 'package:flux/features/customers/blocs/customer_bloc.dart'; import 'package:flux/features/customers/data/customer_repository.dart'; import 'package:flux/features/master_data/products/blocs/product_cubit.dart'; import 'package:flux/features/master_data/products/data/product_repository.dart'; +import 'package:flux/features/master_data/providers/blocs/provider_cubit.dart'; +import 'package:flux/features/master_data/providers/data/provider_repository.dart'; import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart'; import 'package:flux/features/master_data/staff/data/staff_repository.dart'; import 'package:flux/features/master_data/store/bloc/store_cubit.dart'; @@ -64,6 +64,7 @@ Future setupLocator() async { getIt.registerLazySingleton(() => ProductRepository()); getIt.registerLazySingleton(() => StaffRepository()); getIt.registerLazySingleton(() => ServicesRepository()); + getIt.registerLazySingleton(() => ProviderRepository()); } class FluxApp extends StatefulWidget { @@ -103,6 +104,9 @@ class _FluxAppState extends State { BlocProvider( create: (_) => ServicesCubit(context.read()), ), + BlocProvider( + create: (_) => ProvidersCubit(context.read()), + ), ], child: BlocBuilder( builder: (context, state) {