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/theme/theme.dart'; import 'package:flux/core/widgets/flux_text_field.dart'; import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart'; import 'package:flux/features/master_data/staff/models/staff_member_model.dart'; import 'package:flux/features/master_data/store/bloc/store_cubit.dart'; import 'package:get_it/get_it.dart'; class StaffScreen extends StatefulWidget { const StaffScreen({super.key}); @override State createState() => _StaffScreenState(); } class _StaffScreenState extends State { String? _selectedStoreId; bool _showAllCompanyStaff = true; @override void initState() { super.initState(); context.read().loadAllStaff(); } @override Widget build(BuildContext context) { final myRole = context .read() .state .currentStaffMember ?.systemRole; final canManageStaff = myRole == SystemRole.admin || myRole == SystemRole.manager; return Scaffold( backgroundColor: context.background, appBar: AppBar( title: const Text("Anagrafica Personale"), actions: [ Padding( padding: const EdgeInsets.only(right: 16), child: FilterChip( label: const Text("Tutta l'Azienda"), selected: _showAllCompanyStaff, onSelected: (val) => setState(() => _showAllCompanyStaff = val), selectedColor: context.accent.withValues(alpha: 0.2), ), ), ], ), body: BlocListener( listener: (context, state) { if (state.status == StaffStatus.error) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.error ?? 'Errore sconosciuto'), backgroundColor: Colors.red, ), ); } }, child: Column( children: [ // BARRA FILTRO NEGOZIO AnimatedContainer( duration: const Duration(milliseconds: 300), height: _showAllCompanyStaff ? 0 : 80, child: _showAllCompanyStaff ? const SizedBox() : _buildStoreSelector(), ), // LISTA PERSONALE Expanded( child: BlocBuilder( builder: (context, state) { final list = _showAllCompanyStaff ? state.allStaff : (state.staffByStore[_selectedStoreId] ?? []); if (state.status == StaffStatus.loading && list.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (list.isEmpty) return _buildEmptyState(); return ListView.separated( padding: const EdgeInsets.all(16), itemCount: list.length, separatorBuilder: (_, _) => const SizedBox(height: 6), itemBuilder: (context, index) { return _buildStaffCard(list[index]); }, ); }, ), ), ], ), ), floatingActionButton: canManageStaff ? FloatingActionButton.extended( onPressed: () => _openStaffForm(context), label: const Text("Aggiungi"), icon: const Icon(Icons.person_add_alt_1), ) : null, ); } Widget _buildStoreSelector() { return BlocBuilder( builder: (context, state) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: DropdownButtonFormField( initialValue: _selectedStoreId, decoration: const InputDecoration(labelText: "Filtra per Negozio"), items: state.stores .map((s) => DropdownMenuItem(value: s.id, child: Text(s.name))) .toList(), onChanged: (id) { setState(() => _selectedStoreId = id); if (id != null) context.read().loadStaffForStore(id); }, ), ); }, ); } Widget _buildStaffCard(StaffMemberModel member) { final myRole = context .read() .state .currentStaffMember ?.systemRole; final canManageStaff = myRole == SystemRole.admin || myRole == SystemRole.manager; final hasEmail = member.email != null && member.email!.trim().isNotEmpty; return Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: context.accent.withValues(alpha: 0.1)), ), child: ListTile( contentPadding: const EdgeInsets.all(12), leading: CircleAvatar( backgroundColor: context.accent.withValues(alpha: 0.1), child: Text( member.name[0].toUpperCase(), style: TextStyle(color: context.accent), ), ), title: Text( member.name, style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (hasEmail) Text(member.email!), Text( member.phoneNumber != null && member.phoneNumber!.trim().isNotEmpty ? member.phoneNumber! : "Nessun telefono", ), if (member.jobTitle != null && member.jobTitle!.trim().isNotEmpty) ...[ const SizedBox(height: 4), Text( 'Qualifica: ${member.jobTitle!}', style: TextStyle( color: context.accent, fontWeight: FontWeight.w500, ), ), ], ], ), // MODIFICA UX: Menu a tendina per le azioni (Salva spazio e previene overflow) trailing: canManageStaff && hasEmail ? PopupMenuButton( icon: const Icon(Icons.more_vert), onSelected: (value) { if (value == 'invite_reset') { if (!member.hasJoined) { context.read().inviteStaffMember( member: member, selectedStoreIds: member.assignedStores .map((s) => s.id!) .toList(), ); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Invito reinviato, controlla l\'email!', ), ), ); } else { context.read().resetPassword(member.email!); } } }, itemBuilder: (context) => [ PopupMenuItem( value: 'invite_reset', child: Row( children: [ Icon( !member.hasJoined ? Icons.send : Icons.lock_reset, size: 20, ), const SizedBox(width: 12), Text( !member.hasJoined ? "Re-invia Invito" : "Reset Password", ), ], ), ), ], ) : null, onTap: () => canManageStaff ? _openStaffForm(context, member: member) : null, ), ); } void _openStaffForm(BuildContext context, {StaffMemberModel? member}) { final nameController = TextEditingController(text: member?.name); final emailController = TextEditingController(text: member?.email); final phoneController = TextEditingController(text: member?.phoneNumber); final jobTitleController = TextEditingController(text: member?.jobTitle); SystemRole selectedRole = member?.systemRole ?? SystemRole.user; List tempSelectedStores = context .read() .state .storesByStaff[member?.id] ?.map((s) => s.id!) .toList() ?? []; showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => StatefulBuilder( builder: (context, setModalState) { 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( member == null ? "Invita Collaboratore" : "Modifica Collaboratore", style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 24), FluxTextField( controller: nameController, label: "Nome e Cognome", icon: Icons.person, ), const SizedBox(height: 16), FluxTextField( controller: emailController, label: member == null ? "Email (Obbligatoria per invito)*" : "Email", icon: Icons.email, enabled: member == null, ), const SizedBox(height: 16), FluxTextField( controller: phoneController, label: "Telefono", icon: Icons.phone, ), const SizedBox(height: 16), Row( children: [ Expanded( flex: 2, child: DropdownButtonFormField( initialValue: selectedRole, decoration: const InputDecoration( labelText: "Ruolo di Sistema", prefixIcon: Icon(Icons.admin_panel_settings), ), items: SystemRole.values.map((role) { return DropdownMenuItem( value: role, child: Text(role.name.toUpperCase()), ); }).toList(), onChanged: (val) { if (val != null) { setModalState(() => selectedRole = val); } }, ), ), const SizedBox(width: 16), Expanded( flex: 3, child: FluxTextField( controller: jobTitleController, label: "Qualifica (Es. Addetto)", icon: Icons.badge, ), ), ], ), const SizedBox(height: 24), const Text( "Assegna ai Negozi", style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 12), BlocBuilder( builder: (context, storeState) { if (storeState.status == StoreStatus.loading) { return const CircularProgressIndicator(); } return Wrap( spacing: 8, runSpacing: 8, children: storeState.stores.map((store) { final isSelected = tempSelectedStores.contains( store.id, ); return FilterChip( label: Text(store.name), selected: isSelected, onSelected: (selected) { setModalState(() { if (selected) { tempSelectedStores.add(store.id!); } else { tempSelectedStores.remove(store.id); } }); }, selectedColor: context.accent.withValues( alpha: 0.2, ), checkmarkColor: context.accent, ); }).toList(), ); }, ), const SizedBox(height: 32), SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: () { if (member == null && emailController.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( "L'email รจ obbligatoria per invitare!", ), ), ); return; } final updatedMember = StaffMemberModel( id: member?.id, name: nameController.text.trim(), email: emailController.text.trim(), phoneNumber: phoneController.text.trim(), jobTitle: jobTitleController.text.trim(), systemRole: selectedRole, companyId: GetIt.I .get() .state .company! .id!, userId: GetIt.I.get().state.user!.id, ); if (member == null) { context.read().inviteStaffMember( member: updatedMember, selectedStoreIds: tempSelectedStores, ); } else { context.read().saveStaffWithStores( member: updatedMember, selectedStoreIds: tempSelectedStores, ); } Navigator.pop(context); }, child: Text( member == null ? "INVIA INVITO" : "SALVA MODIFICHE", ), ), ), ], ), ), ); }, ), ); } Widget _buildEmptyState() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.people_outline, size: 64, color: context.secondaryText), const SizedBox(height: 16), Text( "Nessun membro trovato", style: TextStyle(color: context.secondaryText), ), ], ), ); } }