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/routes/routes.dart'; import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/utils/extensions.dart'; import 'package:flux/core/widgets/staff_selector_modal.dart'; import 'package:flux/features/home/dashboard_task_list/ui/dashboard_tasks_card.dart'; import 'package:flux/features/home/latest_store_operations/ui/latest_store_operations_card.dart'; import 'package:flux/features/home/latest_store_tickets/ui/latest_store_tickets_card.dart'; import 'package:flux/features/home/ui/quick_actions_widget.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/notes/data/notes_repository.dart'; import 'package:flux/features/notes/models/note_model.dart'; import 'package:flux/features/notes/ui/dashboard_notes_widget.dart'; import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( backgroundColor: theme.colorScheme.surface, body: SafeArea( child: Column( children: [ // ========================================== // 1. HEADER FISSO (Non scrolla mai) // ========================================== Container( padding: const EdgeInsets.all(24.0), // Un leggero colore di sfondo aiuta a staccare l'header quando il contenuto ci passa sotto color: theme.colorScheme.surface, child: _buildHeader(context, theme), ), // ========================================== // 2. CORPO DELLA DASHBOARD (Scrollabile) // ========================================== Expanded( child: CustomScrollView( slivers: [ // --- QUICK ACTIONS: AZIONI RAPIDE --- SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: _buildQuickActions(context), ), ), const SliverToBoxAdapter(child: SizedBox(height: 32)), // --- I WIDGET DELLA DASHBOARD (Responsive Grid) --- SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 24.0), sliver: SliverGrid( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 500, mainAxisSpacing: 16, crossAxisSpacing: 16, childAspectRatio: 1.3, ), delegate: SliverChildListDelegate([ LatestStoreOperationsCard(), LatestStoreTicketsCard(), _buildDashboardWidget( title: context.l10n.homeExpiringContracts, icon: Icons.assignment_late_outlined, color: Colors.orange, context: context, ), DashboardNotesWidget(), DashboardTasksCard(), ]), ), ), // Spazio finale per non far attaccare l'ultima card al fondo const SliverToBoxAdapter(child: SizedBox(height: 40)), ], ), ), ], ), ), ); } // ========================================== // WIDGET BUILDERS // ========================================== Widget _buildHeader(BuildContext context, ThemeData theme) { final user = context.watch().state.currentStaffMember; final currentStore = context.watch().state.currentStore; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( context.l10n.homeWelcomeBack(user?.name ?? "Utente"), style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, letterSpacing: -0.5, color: context.primaryText, // Uso dell'estensione! ), ), const SizedBox(height: 8), InkWell( onTap: () => _showStoreSelector(context, theme), borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: context.primary.withValues( alpha: 0.08, ), // Sfondo delicato borderRadius: BorderRadius.circular(8), border: Border.all( color: context.primary.withValues( alpha: 0.2, ), // Bordino netto ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.storefront, size: 16, color: context.primary), const SizedBox(width: 8), Text( currentStore?.name ?? context.l10n.homeNoStoreFound, style: TextStyle( fontWeight: FontWeight.w600, color: context.primary, ), ), const SizedBox(width: 4), Icon(Icons.arrow_drop_down, color: context.primary), ], ), ), ), ], ), ), CircleAvatar( radius: 24, // Usiamo il Turchese (accent) in trasparenza per l'avatar backgroundColor: context.accent.withValues(alpha: 0.15), child: Icon(Icons.person, color: context.accent, size: 26), ), ], ); } Widget _buildQuickActions(BuildContext context) { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ QuickActionButton( icon: Icons.add, label: context.l10n.commonOperation, color: Colors.blue, onTap: () async { StaffMemberModel? createdBy = await getStaffMember(context); if (createdBy == null || !context.mounted) return; context.pushNamed( Routes.operationForm, pathParameters: {'id': 'new'}, extra: (createdBy: createdBy, operation: null), ); }, ), const SizedBox(width: 12), QuickActionButton( icon: Icons.handyman, label: context.l10n.homeNewOperationTicket, color: Colors.redAccent, onTap: () async { StaffMemberModel? createdBy = await getStaffMember(context); if (createdBy == null || !context.mounted) return; context.pushNamed( Routes.ticketForm, pathParameters: {'id': 'new'}, extra: (createdBy: createdBy, ticket: null), ); }, ), const SizedBox(width: 12), QuickActionButton( icon: Icons.note_add, label: context.l10n.commonNote, color: Colors.amber, onTap: () async { final companyId = context.read().state.company!.id!; final currentStaffId = context .read() .state .currentStaffMember! .id!; final emptyNote = NoteModel.empty( createdBy: currentStaffId, companyId: companyId, ); final noteId = await GetIt.I.get().saveNote( emptyNote, ); if (!context.mounted) return; context.pushNamed( Routes.noteForm, pathParameters: {'id': noteId}, extra: emptyNote.copyWith(id: noteId), ); }, ), const SizedBox(width: 12), QuickActionButton( icon: Icons.task_alt, label: context.l10n.commonTask, color: Colors.teal, onTap: () { context.pushNamed(Routes.taskForm, pathParameters: {'id': 'new'}); }, ), ], ), ); } Widget _buildDashboardWidget({ required BuildContext context, required String title, required IconData icon, required Color color, VoidCallback? onTap, }) { final theme = Theme.of(context); return Card( elevation: 0, clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: theme.dividerColor.withValues(alpha: 0.5)), ), child: InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: color, size: 20), ), const SizedBox(width: 12), Expanded( child: Text( title, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: context.primaryText, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), IconButton( icon: Icon( Icons.more_vert, size: 20, color: context.secondaryText, ), onPressed: () {}, padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), ], ), const Spacer(), Center( child: Text( context.l10n.commonComingSoon, style: TextStyle( color: context.secondaryText.withValues(alpha: 0.7), fontStyle: FontStyle.italic, fontSize: 13, ), ), ), const Spacer(), ], ), ), ), ); } void _showStoreSelector(BuildContext context, ThemeData theme) { showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), builder: (context) { // Leggiamo la lista dei negozi dal Cubit dedicato (se ce l'hai lì) // Oppure adatta il blocco se li salvi altrove! final staffState = context.watch().state; final currentStoreId = context .read() .state .currentStore ?.id; final currentStaffId = context .read() .state .currentStaffMember ?.id; return SafeArea( child: Padding( padding: const EdgeInsets.symmetric(vertical: 24.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Text( "Seleziona Negozio", style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 16), if (staffState.status == StaffStatus.loading) const Center(child: CircularProgressIndicator()) else if (staffState.storesByStaff[currentStaffId] == null) const Padding( padding: EdgeInsets.all(24.0), child: Text("Nessun negozio disponibile."), ) else ...staffState.storesByStaff[currentStaffId]!.map((store) { final isSelected = store.id == currentStoreId; return ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 24.0, ), leading: Icon( Icons.storefront, color: isSelected ? theme.colorScheme.primary : theme.iconTheme.color, ), title: Text( store.name, style: TextStyle( fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, color: isSelected ? theme.colorScheme.primary : null, ), ), trailing: isSelected ? Icon( Icons.check_circle, color: theme.colorScheme.primary, ) : null, onTap: () { // Cambiamo il negozio nel SessionCubit! context.read().changeStore(store); context.read().loadStaffForStore(store.id!); Navigator.pop(context); }, ); }), ], ), ), ); }, ); } }