Fix: Gestione dipendenti nei negozi funzionante con doppio Cubit e UI reattiva

This commit is contained in:
2026-04-15 09:58:27 +02:00
parent 7b3dc449a6
commit 92febadd61
3 changed files with 111 additions and 40 deletions

View File

@@ -1,6 +1,8 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flux/core/blocs/session/session_bloc.dart'; import 'package:flux/core/blocs/session/session_bloc.dart';
import 'package:flux/features/master_data/staff/data/staff_repository.dart';
import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
import 'package:flux/features/master_data/store/data/store_repository.dart'; import 'package:flux/features/master_data/store/data/store_repository.dart';
import 'package:flux/features/master_data/store/models/store_model.dart'; import 'package:flux/features/master_data/store/models/store_model.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
@@ -9,6 +11,7 @@ part 'store_state.dart';
class StoreCubit extends Cubit<StoreState> { class StoreCubit extends Cubit<StoreState> {
final StoreRepository _repository = GetIt.I<StoreRepository>(); final StoreRepository _repository = GetIt.I<StoreRepository>();
final StaffRepository _staffRepository = GetIt.I<StaffRepository>();
final SessionBloc _sessionBloc; final SessionBloc _sessionBloc;
StoreCubit(this._sessionBloc) : super(const StoreState(stores: [])); StoreCubit(this._sessionBloc) : super(const StoreState(stores: []));
@@ -31,10 +34,17 @@ class StoreCubit extends Cubit<StoreState> {
final stores = await _repository.getStoresByCompany( final stores = await _repository.getStoresByCompany(
_sessionBloc.state.company!.id, _sessionBloc.state.company!.id,
); );
final Map<String, List<StaffMemberModel>> staffByStore = {};
for (StoreModel store in stores) {
staffByStore[store.id!] = await _staffRepository.getStaffMembersInStore(
store.id!,
);
}
emit( emit(
state.copyWith( state.copyWith(
status: StoreStatus.success, status: StoreStatus.success,
stores: stores, // Assicurati di avere 'stores' nello StoreState stores: stores,
staffByStore: staffByStore,
), ),
); );
} catch (e) { } catch (e) {
@@ -43,4 +53,45 @@ class StoreCubit extends Cubit<StoreState> {
); );
} }
} }
Future<void> assignStaffToStore(String storeId, String staffId) async {
try {
await _staffRepository.assignToStore(staffId, storeId);
// Dopo l'assegnazione, potresti voler ricaricare lo staff per quel negozio
final updatedStaff = await _staffRepository.getStaffMembersInStore(
storeId,
);
final newMap = Map<String, List<StaffMemberModel>>.from(
state.staffByStore,
);
newMap[storeId] = updatedStaff;
emit(state.copyWith(status: StoreStatus.success, staffByStore: newMap));
} catch (e) {
emit(
state.copyWith(status: StoreStatus.failure, errorMessage: e.toString()),
);
}
}
// Rimuove un dipendente da un negozio
Future<void> removeStaffFromStore(String staffId, String storeId) async {
try {
await _staffRepository.removeFromStore(staffId, storeId);
final updatedStaff = await _staffRepository.getStaffMembersInStore(
storeId,
);
final newMap = Map<String, List<StaffMemberModel>>.from(
state.staffByStore,
);
newMap[storeId] = updatedStaff;
emit(state.copyWith(staffByStore: newMap));
} catch (e) {
emit(
state.copyWith(
status: StoreStatus.failure,
errorMessage: "Errore nella rimozione: $e",
),
);
}
}
} }

View File

@@ -7,12 +7,14 @@ class StoreState extends Equatable {
final StoreModel? store; final StoreModel? store;
final String? errorMessage; final String? errorMessage;
final List<StoreModel> stores; final List<StoreModel> stores;
final Map<String, List<StaffMemberModel>> staffByStore;
const StoreState({ const StoreState({
this.status = StoreStatus.initial, this.status = StoreStatus.initial,
this.store, this.store,
this.errorMessage, this.errorMessage,
required this.stores, required this.stores,
this.staffByStore = const {},
}); });
StoreState copyWith({ StoreState copyWith({
@@ -20,15 +22,23 @@ class StoreState extends Equatable {
StoreModel? store, StoreModel? store,
String? errorMessage, String? errorMessage,
List<StoreModel>? stores, List<StoreModel>? stores,
Map<String, List<StaffMemberModel>>? staffByStore,
}) { }) {
return StoreState( return StoreState(
status: status ?? this.status, status: status ?? this.status,
store: store ?? this.store, store: store ?? this.store,
errorMessage: errorMessage ?? this.errorMessage, errorMessage: errorMessage ?? this.errorMessage,
stores: stores ?? this.stores, stores: stores ?? this.stores,
staffByStore: staffByStore ?? this.staffByStore,
); );
} }
@override @override
List<Object?> get props => [status, store, errorMessage, stores]; List<Object?> get props => [
status,
store,
errorMessage,
stores,
staffByStore,
];
} }

View File

@@ -90,10 +90,10 @@ class _StoresScreenState extends State<StoresScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// Mostra quanti dipendenti ci sono (usando lo StaffCubit) // Mostra quanti dipendenti ci sono (usando lo StaffCubit)
BlocBuilder<StaffCubit, StaffState>( BlocBuilder<StoreCubit, StoreState>(
builder: (context, staffState) { builder: (context, storeState) {
final staffCount = final staffCount =
staffState.storesByStaff[store.id]?.length ?? 0; storeState.staffByStore[store.id]?.length ?? 0;
return ActionChip( return ActionChip(
avatar: const Icon(Icons.people, size: 16), avatar: const Icon(Icons.people, size: 16),
label: Text("$staffCount Dipendenti"), label: Text("$staffCount Dipendenti"),
@@ -119,33 +119,41 @@ class _StoresScreenState extends State<StoresScreen> {
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) => BlocBuilder<StaffCubit, StaffState>( builder: (context) => BlocBuilder<StaffCubit, StaffState>(
builder: (context, state) { // 1. Prendi TUTTI i dipendenti
builder: (context, staffState) {
return BlocBuilder<StoreCubit, StoreState>(
// 2. Prendi le ASSEGNAZIONI
builder: (context, storeState) {
final assignedToThisStore =
storeState.staffByStore[store.id!] ?? [];
return Container( return Container(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text("Personale di ${store.nome}", style: context.titleLarge), Text(
"Personale di ${store.nome}",
style: context.titleLarge,
),
const SizedBox(height: 16), const SizedBox(height: 16),
// Lista di TUTTO lo staff dell'azienda con checkbox ...staffState.allStaff.map((person) {
...state.allStaff.map((person) { // La spunta deve dipendere dallo StoreCubit!
final bool isAssigned = final bool isAssigned = assignedToThisStore.any(
state.storesByStaff[store.id!]?.any(
(s) => s.id == person.id, (s) => s.id == person.id,
) ?? );
false;
return CheckboxListTile( return CheckboxListTile(
title: Text(person.name), title: Text(person.name),
value: isAssigned, value: isAssigned,
onChanged: (selected) { onChanged: (selected) {
if (selected == true) { if (selected == true) {
context.read<StaffCubit>().assignMemberToStore( context.read<StoreCubit>().assignStaffToStore(
person.id!,
store.id!, store.id!,
person.id!,
); );
} else { } else {
context.read<StaffCubit>().removeMemberFromStore( context.read<StoreCubit>().removeStaffFromStore(
person.id!, person.id!,
store.id!, store.id!,
); );
@@ -157,6 +165,8 @@ class _StoresScreenState extends State<StoresScreen> {
), ),
); );
}, },
);
},
), ),
); );
} }