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'; // Tuo percorso 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; // Partiamo con la vista globale @override void initState() { super.initState(); // Carichiamo subito tutto context.read().loadAllStaff(); } @override Widget build(BuildContext context) { // 1. Peschiamo chi siamo noi e che poteri abbiamo 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: [ // Toggle per vista Azienda / Negozio 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 (Visibile solo se non 'Tutta l'Azienda') --- 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: 12), itemBuilder: (context, index) { final member = list[index]; return _buildStaffCard(member); }, ); }, ), ), ], ), ), floatingActionButton: canManageStaff ? FloatingActionButton.extended( onPressed: () => _openStaffForm(context), label: const Text("Aggiungi"), icon: const Icon(Icons.person_add_alt_1), ) : null, ); } Widget _buildStoreSelector() { return BlocBuilder( // Assumendo tu abbia uno StoreCubit 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.nome))) .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; 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], style: TextStyle(color: context.accent)), ), title: Text( member.name, style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (member.email != null && member.email!.isNotEmpty) Text(member.email!), Text( member.phoneNumber != null && member.phoneNumber!.isNotEmpty ? member.phoneNumber! : "Nessun telefono", ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (member.jobTitle != null && member.jobTitle!.isNotEmpty) ...[ Text('Qualifica: ${member.jobTitle!}'), const SizedBox(width: 8), ], if (canManageStaff) ...[ const SizedBox(width: 8), if (!member.hasJoined) ElevatedButton.icon( icon: const Icon(Icons.send), label: const Text("Re-invia Invito (In Attesa)"), style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, ), onPressed: () { // Chiama la funzione di reset password mascherata da invito context.read().resetPasswordOrResendInviteLink( member.email!, ); }, ) else OutlinedButton.icon( icon: const Icon(Icons.lock_reset), label: const Text("Invia Reset Password"), onPressed: () { // Chiama LA STESSA IDENTICA FUNZIONE! context.read().resetPasswordOrResendInviteLink( member.email!, ); }, ), ], ], ), 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); // Variabili di stato per il BottomSheet 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" // Cambiato il titolo per chiarezza! : "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), // Reso visivamente obbligatorio se è un nuovo utente FluxTextField( controller: emailController, label: member == null ? "Email (Obbligatoria per invito)*" : "Email", icon: Icons.email, enabled: member == null, // UX: Di solito l'email non si cambia dopo l'invito ), const SizedBox(height: 16), FluxTextField( controller: phoneController, label: "Telefono", icon: Icons.phone, ), const SizedBox(height: 16), // --- NOVITÀ: SCELTA DEL RUOLO E MANSIONE --- 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.nome), 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: () { // Validazione di base per i nuovi inviti 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, // Sarà null se è nuovo 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, ); // --- IL BIVIO LOGICO MAGICO --- if (member == null) { // 1. UTENTE NUOVO -> Chiamiamo la Edge Function // (Nota: Per i negozi, potresti dover fare una logica a parte nel Cubit // perché l'ID del database viene generato DOPO che l'Edge Function ha finito) context.read().inviteStaffMember( member: updatedMember, selectedStoreIds: tempSelectedStores, ); } else { // 2. UTENTE ESISTENTE -> Modifica classica context.read().saveStaffWithStores( member: updatedMember, selectedStoreIds: tempSelectedStores, ); } Navigator.pop(context); }, child: Text( member == null ? "INVIA INVITO" : "SALVA MODIFICHE", ), ), ), /* const SizedBox(height: 16), if (!member!.hasJoined) ElevatedButton.icon( icon: const Icon(Icons.send), label: const Text("Re-invia Invito (In Attesa)"), style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, ), onPressed: () { // Chiama la funzione di reset password mascherata da invito context .read() .resetPasswordOrResendInviteLink(member.email!); }, ) else OutlinedButton.icon( icon: const Icon(Icons.lock_reset), label: const Text("Invia Reset Password"), onPressed: () { // Chiama LA STESSA IDENTICA FUNZIONE! context .read() .resetPasswordOrResendInviteLink(member.email!); }, ), */ ], ), ), ); }, ), ); } 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), ), ], ), ); } }