import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../../l10n/app_localizations.dart'; import '../../models/bar_tab.dart'; import '../../models/tab_item_purchase.dart'; class OpenTabHistoryCard extends StatefulWidget { final BarTab tab; const OpenTabHistoryCard({super.key, required this.tab}); @override State createState() => _OpenTabHistoryCardState(); } class _OpenTabHistoryCardState extends State { bool _expanded = false; List<_OpenPurchase> _purchases(BarTab tab) { final purchases = <_OpenPurchase>[]; for (final item in tab.items) { final records = item.purchases.isEmpty ? List.generate( item.quantity, (index) => TabItemPurchase( id: '${item.id}-$index', tabItemId: item.id, purchasedAt: tab.openedAt, ), ) : item.purchases; purchases.addAll( records.map( (purchase) => _OpenPurchase( productName: item.productName, unitPriceInCents: item.unitPriceInCents, purchasedAt: purchase.purchasedAt, isRemoved: purchase.isRemoved, ), ), ); } purchases.sort((a, b) { final byTime = b.purchasedAt.compareTo(a.purchasedAt); if (byTime != 0) return byTime; return b.productName.compareTo(a.productName); }); return purchases; } @override Widget build(BuildContext context) { final tab = widget.tab; final l10n = AppLocalizations.of(context); final locale = Localizations.localeOf(context).toLanguageTag(); final dateFormat = DateFormat.yMMMd(locale).add_jm(); final scheme = Theme.of(context).colorScheme; return Container( decoration: BoxDecoration( color: scheme.primary.withValues(alpha: 0.06), borderRadius: BorderRadius.circular(14), border: Border.all(color: scheme.primary.withValues(alpha: 0.2)), ), clipBehavior: Clip.antiAlias, child: Material( color: Colors.transparent, child: InkWell( onTap: () => setState(() => _expanded = !_expanded), enableFeedback: true, splashFactory: NoSplash.splashFactory, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( tab.customerName, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: scheme.onSurface, ), ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 3, ), decoration: BoxDecoration( color: scheme.primary.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(999), ), child: Text( l10n.openTabs, style: TextStyle( fontSize: 11, fontWeight: FontWeight.w700, color: scheme.primary, ), ), ), ], ), const SizedBox(height: 2), Text( '${dateFormat.format(tab.openedAt)} · ${l10n.tabItemCount(tab.itemCount)}', style: Theme.of(context).textTheme.bodySmall, ), ], ), ), const SizedBox(width: 8), Text( tab.formattedTotal, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: scheme.onSurface, ), ), const SizedBox(width: 4), Icon( _expanded ? Icons.expand_less_rounded : Icons.expand_more_rounded, color: scheme.onSurface.withValues(alpha: 0.5), ), ], ), ), AnimatedCrossFade( duration: const Duration(milliseconds: 150), crossFadeState: _expanded ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 14), child: Column( children: [ const Divider(height: 1), const SizedBox(height: 8), ..._purchases( tab, ).map((purchase) => _OpenPurchaseRow(purchase: purchase)), ], ), ), secondChild: const SizedBox(width: double.infinity), ), ], ), ), ), ); } } class _OpenPurchase { final String productName; final int unitPriceInCents; final DateTime purchasedAt; final bool isRemoved; const _OpenPurchase({ required this.productName, required this.unitPriceInCents, required this.purchasedAt, required this.isRemoved, }); } class _OpenPurchaseRow extends StatelessWidget { final _OpenPurchase purchase; const _OpenPurchaseRow({required this.purchase}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final locale = Localizations.localeOf(context).toLanguageTag(); final dateFormat = DateFormat.yMMMd(locale).add_jm(); final unitPrice = NumberFormat.simpleCurrency( locale: locale, ).format(purchase.unitPriceInCents / 100); final scheme = Theme.of(context).colorScheme; return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( purchase.productName, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w600, color: purchase.isRemoved ? scheme.onSurface.withValues(alpha: 0.5) : scheme.onSurface, decoration: purchase.isRemoved ? TextDecoration.lineThrough : null, ), ), Text( dateFormat.format(purchase.purchasedAt), style: Theme.of(context).textTheme.bodySmall, ), ], ), ), if (purchase.isRemoved) Text( l10n.removed, style: TextStyle( color: scheme.error, fontSize: 12, fontWeight: FontWeight.w700, ), ) else Text( '1 × $unitPrice', style: Theme.of(context).textTheme.bodySmall, ), ], ), ); } }