Refactor StoreBloc to Cubit and Fix Staff Assignment UI #1

Merged
brontomark merged 2 commits from fix-StoreScreen into main 2026-04-15 10:05:07 +02:00
3 changed files with 111 additions and 40 deletions
Showing only changes of commit 92febadd61 - Show all commits

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,42 +119,52 @@ 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
return Container( builder: (context, staffState) {
padding: const EdgeInsets.all(24), return BlocBuilder<StoreCubit, StoreState>(
child: Column( // 2. Prendi le ASSEGNAZIONI
mainAxisSize: MainAxisSize.min, builder: (context, storeState) {
children: [ final assignedToThisStore =
Text("Personale di ${store.nome}", style: context.titleLarge), storeState.staffByStore[store.id!] ?? [];
const SizedBox(height: 16),
// Lista di TUTTO lo staff dell'azienda con checkbox
...state.allStaff.map((person) {
final bool isAssigned =
state.storesByStaff[store.id!]?.any(
(s) => s.id == person.id,
) ??
false;
return CheckboxListTile( return Container(
title: Text(person.name), padding: const EdgeInsets.all(24),
value: isAssigned, child: Column(
onChanged: (selected) { mainAxisSize: MainAxisSize.min,
if (selected == true) { children: [
context.read<StaffCubit>().assignMemberToStore( Text(
person.id!, "Personale di ${store.nome}",
store.id!, style: context.titleLarge,
); ),
} else { const SizedBox(height: 16),
context.read<StaffCubit>().removeMemberFromStore( ...staffState.allStaff.map((person) {
person.id!, // La spunta deve dipendere dallo StoreCubit!
store.id!, final bool isAssigned = assignedToThisStore.any(
); (s) => s.id == person.id,
} );
},
); return CheckboxListTile(
}), title: Text(person.name),
], value: isAssigned,
), onChanged: (selected) {
if (selected == true) {
context.read<StoreCubit>().assignStaffToStore(
store.id!,
person.id!,
);
} else {
context.read<StoreCubit>().removeStaffFromStore(
person.id!,
store.id!,
);
}
},
);
}),
],
),
);
},
); );
}, },
), ),