import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import '../../l10n/app_localizations.dart'; import '../../models/bar_tab.dart'; import '../../models/tab_item.dart'; import '../../utils/money.dart'; import 'selected_tab_details.dart'; class TabPanel extends StatefulWidget { final List tabs; final BarTab? selectedTab; final String? selectedTabId; final Map stockByProductId; final VoidCallback onNewTabPressed; final ValueChanged onTabSelected; final Future Function(TabItem item, int delta) onItemQuantityChanged; final VoidCallback onCloseTabPressed; final Future Function(BarTab) onTabEdited; final Future Function(BarTab) onTabDeleted; const TabPanel({ super.key, required this.tabs, required this.selectedTab, required this.selectedTabId, required this.stockByProductId, required this.onNewTabPressed, required this.onTabSelected, required this.onItemQuantityChanged, required this.onCloseTabPressed, required this.onTabEdited, required this.onTabDeleted, }); @override State createState() => _TabPanelState(); } class _TabPanelState extends State { final TextEditingController _searchController = TextEditingController(); String _searchQuery = ''; @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; final l10n = AppLocalizations.of(context); final filteredTabs = widget.tabs.where((tab) { return tab.customerName.toLowerCase().contains( _searchQuery.toLowerCase(), ); }).toList(); return DecoratedBox( decoration: BoxDecoration(color: scheme.surfaceContainerLow), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: TextField( controller: _searchController, onChanged: (value) { setState(() { _searchQuery = value; }); }, decoration: InputDecoration( hintText: l10n.searchByName, prefixIcon: Icon(Icons.search_rounded, size: 20), suffixIcon: _searchQuery.isEmpty ? null : IconButton( onPressed: () { _searchController.clear(); setState(() { _searchQuery = ''; }); }, icon: const Icon(Icons.clear_rounded), tooltip: l10n.clearSearch, ), isDense: true, ), ), ), const SizedBox(width: 10), IconButton.filled( onPressed: widget.onNewTabPressed, icon: const Icon(Icons.add_rounded), tooltip: l10n.openNewTab, ), ], ), const SizedBox(height: 8), SizedBox( height: 190, child: OpenTabsList( tabs: filteredTabs, selectedTabId: widget.selectedTabId, onTabSelected: widget.onTabSelected, onTabEdited: widget.onTabEdited, onTabDeleted: widget.onTabDeleted, ), ), const Divider(height: 28), Expanded( child: widget.selectedTab == null ? Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.receipt_long_outlined, size: 36, color: scheme.onSurface.withValues(alpha: 0.25), ), const SizedBox(height: 10), Text( l10n.selectOrOpenTab, style: Theme.of(context).textTheme.bodyMedium, ), ], ), ) : SelectedTabDetails( tab: widget.selectedTab!, stockByProductId: widget.stockByProductId, onItemQuantityChanged: widget.onItemQuantityChanged, onCloseTabPressed: widget.onCloseTabPressed, ), ), ], ), ), ); } } class OpenTabsList extends StatelessWidget { final List tabs; final String? selectedTabId; final ValueChanged onTabSelected; final Future Function(BarTab) onTabEdited; final Future Function(BarTab) onTabDeleted; const OpenTabsList({ super.key, required this.tabs, required this.selectedTabId, required this.onTabSelected, required this.onTabEdited, required this.onTabDeleted, }); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); if (tabs.isEmpty) { return Center( child: Text( l10n.noOpenTabs, style: Theme.of(context).textTheme.bodyMedium, ), ); } return ListView.separated( itemCount: tabs.length, separatorBuilder: (_, _) => const SizedBox(height: 8), itemBuilder: (context, index) { final tab = tabs[index]; final selected = tab.id == selectedTabId; final scheme = Theme.of(context).colorScheme; final primary = scheme.primary; return ClipRRect( borderRadius: BorderRadius.circular(14), child: Slidable( key: ValueKey(tab.id), endActionPane: ActionPane( motion: const DrawerMotion(), extentRatio: 0.6, children: [ SlidableAction( onPressed: (_) => onTabEdited(tab), icon: Icons.edit_outlined, label: l10n.edit, backgroundColor: Theme.of(context).colorScheme.secondary, foregroundColor: Theme.of(context).colorScheme.onSecondary, ), SlidableAction( onPressed: (_) => onTabDeleted(tab), icon: Icons.delete_outline_rounded, label: l10n.delete, backgroundColor: Theme.of(context).colorScheme.error, foregroundColor: Theme.of(context).colorScheme.onError, ), ], ), child: AnimatedContainer( duration: const Duration(milliseconds: 150), decoration: BoxDecoration( color: selected ? primary.withValues(alpha: 0.14) : scheme.onSurface.withValues(alpha: 0.04), borderRadius: BorderRadius.circular(14), border: Border.all( color: selected ? primary.withValues(alpha: 0.6) : scheme.onSurface.withValues(alpha: 0.06), width: selected ? 1.4 : 1, ), ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(14), onTap: () => onTabSelected(tab.id), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), child: SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( tab.customerName, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: scheme.onSurface, ), ), const SizedBox(height: 4), Text( l10n.tabItemSummary( tab.itemCount, tab.totalInCents.asEuro, ), style: Theme.of(context).textTheme.bodySmall, ), ], ), ), ), ), ), ), ), ); }, ); } }