import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../../common/theme/theme.dart'; class Transaction { final String id; final String customerName; final DateTime date; final double total; final String status; final List items; final String paymentMethod; Transaction({ required this.id, required this.customerName, required this.date, required this.total, required this.status, required this.items, required this.paymentMethod, }); } class TransactionItem { final String name; final int quantity; final double price; TransactionItem({ required this.name, required this.quantity, required this.price, }); } @RoutePage() class TransactionPage extends StatefulWidget { const TransactionPage({super.key}); @override State createState() => _TransactionPageState(); } class _TransactionPageState extends State { String selectedFilter = 'All'; DateTime selectedDate = DateTime.now(); final List transactions = [ Transaction( id: 'TRX001', customerName: 'Ahmad Rizki', date: DateTime.now().subtract(Duration(hours: 2)), total: 125000, status: 'Completed', paymentMethod: 'Cash', items: [ TransactionItem(name: 'Nasi Goreng', quantity: 2, price: 25000), TransactionItem(name: 'Es Teh', quantity: 3, price: 5000), TransactionItem(name: 'Ayam Bakar', quantity: 1, price: 35000), ], ), Transaction( id: 'TRX002', customerName: 'Siti Nurhaliza', date: DateTime.now().subtract(Duration(hours: 4)), total: 85000, status: 'Completed', paymentMethod: 'QRIS', items: [ TransactionItem(name: 'Gado-gado', quantity: 1, price: 20000), TransactionItem(name: 'Jus Jeruk', quantity: 2, price: 12000), TransactionItem(name: 'Kerupuk', quantity: 1, price: 5000), ], ), Transaction( id: 'TRX003', customerName: 'Budi Santoso', date: DateTime.now().subtract(Duration(hours: 6)), total: 200000, status: 'Pending', paymentMethod: 'Debit Card', items: [ TransactionItem(name: 'Paket Keluarga', quantity: 1, price: 150000), TransactionItem(name: 'Es Campur', quantity: 2, price: 15000), ], ), ]; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.background, appBar: AppBar( elevation: 0, backgroundColor: AppColor.white, title: Text( 'Transactions', style: TextStyle( color: AppColor.textPrimary, fontSize: 20, fontWeight: FontWeight.bold, ), ), actions: [ IconButton( icon: Icon(Icons.search, color: AppColor.textPrimary), onPressed: () {}, ), IconButton( icon: Icon(Icons.filter_list, color: AppColor.textPrimary), onPressed: () => _showFilterBottomSheet(context), ), ], ), body: Column( children: [ _buildSummaryCards(), _buildFilterTabs(), Expanded(child: _buildTransactionList()), ], ), floatingActionButton: FloatingActionButton.extended( onPressed: () {}, backgroundColor: AppColor.primary, icon: Icon(Icons.add, color: AppColor.white), label: Text( 'New Sale', style: TextStyle(color: AppColor.white, fontWeight: FontWeight.w600), ), ), ); } Widget _buildSummaryCards() { return Container( padding: EdgeInsets.all(16), child: Row( children: [ Expanded( child: _buildSummaryCard( 'Today\'s Sales', 'Rp 2,450,000', Icons.trending_up, AppColor.success, '+12%', ), ), SizedBox(width: 12), Expanded( child: _buildSummaryCard( 'Total Orders', '48', Icons.receipt_long, AppColor.info, '+8%', ), ), ], ), ); } Widget _buildSummaryCard( String title, String value, IconData icon, Color color, String change, ) { return Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: AppColor.black.withOpacity(0.05), blurRadius: 10, offset: Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(icon, color: color, size: 24), Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppColor.success.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( change, style: TextStyle( color: AppColor.success, fontSize: 10, fontWeight: FontWeight.w600, ), ), ), ], ), SizedBox(height: 12), Text( value, style: TextStyle( color: AppColor.textPrimary, fontSize: 20, fontWeight: FontWeight.bold, ), ), SizedBox(height: 4), Text( title, style: TextStyle( color: AppColor.textSecondary, fontSize: 12, fontWeight: FontWeight.w500, ), ), ], ), ); } Widget _buildFilterTabs() { final filters = ['All', 'Completed', 'Pending', 'Cancelled']; return Container( height: 60, padding: EdgeInsets.symmetric(horizontal: 16), child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: filters.length, itemBuilder: (context, index) { final filter = filters[index]; final isSelected = selectedFilter == filter; return GestureDetector( onTap: () { setState(() { selectedFilter = filter; }); }, child: Container( margin: EdgeInsets.only(right: 12, top: 8, bottom: 8), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 8), decoration: BoxDecoration( color: isSelected ? AppColor.primary : AppColor.white, borderRadius: BorderRadius.circular(25), border: Border.all( color: isSelected ? AppColor.primary : AppColor.border, width: 1, ), ), child: Text( filter, style: TextStyle( color: isSelected ? AppColor.white : AppColor.textSecondary, fontWeight: FontWeight.w600, fontSize: 14, ), ), ), ); }, ), ); } Widget _buildTransactionList() { final filteredTransactions = transactions.where((transaction) { if (selectedFilter == 'All') return true; return transaction.status == selectedFilter; }).toList(); return ListView.builder( padding: EdgeInsets.symmetric(horizontal: 16), itemCount: filteredTransactions.length, itemBuilder: (context, index) { final transaction = filteredTransactions[index]; return _buildTransactionCard(transaction); }, ); } Widget _buildTransactionCard(Transaction transaction) { return GestureDetector( onTap: () => _showTransactionDetail(transaction), child: Container( margin: EdgeInsets.only(bottom: 12), padding: EdgeInsets.all(16), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: AppColor.black.withOpacity(0.05), blurRadius: 10, offset: Offset(0, 2), ), ], ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( transaction.id, style: TextStyle( color: AppColor.textPrimary, fontSize: 16, fontWeight: FontWeight.bold, ), ), SizedBox(height: 4), Text( transaction.customerName, style: TextStyle( color: AppColor.textSecondary, fontSize: 14, ), ), SizedBox(height: 4), Text( '${_formatTime(transaction.date)} • ${transaction.paymentMethod}', style: TextStyle( color: AppColor.textLight, fontSize: 12, ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( 'Rp ${_formatCurrency(transaction.total)}', style: TextStyle( color: AppColor.textPrimary, fontSize: 16, fontWeight: FontWeight.bold, ), ), SizedBox(height: 8), Container( padding: EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: _getStatusColor( transaction.status, ).withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Text( transaction.status, style: TextStyle( color: _getStatusColor(transaction.status), fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ], ), ], ), SizedBox(height: 12), Row( children: [ Icon( Icons.shopping_bag_outlined, color: AppColor.textLight, size: 16, ), SizedBox(width: 8), Text( '${transaction.items.length} items', style: TextStyle(color: AppColor.textLight, fontSize: 12), ), Spacer(), Icon( Icons.arrow_forward_ios, color: AppColor.textLight, size: 14, ), ], ), ], ), ), ); } Color _getStatusColor(String status) { switch (status) { case 'Completed': return AppColor.success; case 'Pending': return AppColor.warning; case 'Cancelled': return AppColor.error; default: return AppColor.textSecondary; } } String _formatCurrency(double amount) { return amount .toStringAsFixed(0) .replaceAllMapped( RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},', ); } String _formatTime(DateTime dateTime) { final now = DateTime.now(); final difference = now.difference(dateTime); if (difference.inHours < 1) { return '${difference.inMinutes}m ago'; } else if (difference.inHours < 24) { return '${difference.inHours}h ago'; } else { return '${difference.inDays}d ago'; } } void _showFilterBottomSheet(BuildContext context) { showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (context) { return Container( padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Filter Transactions', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColor.textPrimary, ), ), SizedBox(height: 20), _buildFilterOption('Date Range', Icons.date_range), _buildFilterOption('Payment Method', Icons.payment), _buildFilterOption('Amount Range', Icons.attach_money), _buildFilterOption('Customer', Icons.person), SizedBox(height: 20), Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(context), style: OutlinedButton.styleFrom( side: BorderSide(color: AppColor.border), padding: EdgeInsets.symmetric(vertical: 12), ), child: Text( 'Reset', style: TextStyle(color: AppColor.textSecondary), ), ), ), SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () => Navigator.pop(context), style: ElevatedButton.styleFrom( backgroundColor: AppColor.primary, padding: EdgeInsets.symmetric(vertical: 12), ), child: Text( 'Apply', style: TextStyle(color: AppColor.white), ), ), ), ], ), ], ), ); }, ); } Widget _buildFilterOption(String title, IconData icon) { return ListTile( contentPadding: EdgeInsets.zero, leading: Icon(icon, color: AppColor.textSecondary), title: Text(title, style: TextStyle(color: AppColor.textPrimary)), trailing: Icon( Icons.arrow_forward_ios, size: 16, color: AppColor.textLight, ), onTap: () {}, ); } void _showTransactionDetail(Transaction transaction) { showModalBottomSheet( context: context, isScrollControlled: true, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (context) { return DraggableScrollableSheet( initialChildSize: 0.7, maxChildSize: 0.9, minChildSize: 0.5, builder: (context, scrollController) { return Container( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Container( width: 40, height: 4, decoration: BoxDecoration( color: AppColor.borderLight, borderRadius: BorderRadius.circular(2), ), ), ), SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Transaction Detail', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColor.textPrimary, ), ), Container( padding: EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: _getStatusColor( transaction.status, ).withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Text( transaction.status, style: TextStyle( color: _getStatusColor(transaction.status), fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ], ), SizedBox(height: 20), _buildDetailRow('Transaction ID', transaction.id), _buildDetailRow('Customer', transaction.customerName), _buildDetailRow( 'Date', '${transaction.date.day}/${transaction.date.month}/${transaction.date.year}', ), _buildDetailRow('Payment Method', transaction.paymentMethod), SizedBox(height: 20), Text( 'Items Ordered', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColor.textPrimary, ), ), SizedBox(height: 12), Expanded( child: ListView.builder( controller: scrollController, itemCount: transaction.items.length, itemBuilder: (context, index) { final item = transaction.items[index]; return Container( margin: EdgeInsets.only(bottom: 8), padding: EdgeInsets.all(12), decoration: BoxDecoration( color: AppColor.backgroundLight, borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.name, style: TextStyle( color: AppColor.textPrimary, fontWeight: FontWeight.w600, ), ), Text( 'Qty: ${item.quantity}', style: TextStyle( color: AppColor.textSecondary, fontSize: 12, ), ), ], ), ), Text( 'Rp ${_formatCurrency(item.price * item.quantity)}', style: TextStyle( color: AppColor.textPrimary, fontWeight: FontWeight.bold, ), ), ], ), ); }, ), ), Container( padding: EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( border: Border(top: BorderSide(color: AppColor.border)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Total Amount', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColor.textPrimary, ), ), Text( 'Rp ${_formatCurrency(transaction.total)}', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColor.primary, ), ), ], ), ), ], ), ); }, ); }, ); } Widget _buildDetailRow(String label, String value) { return Padding( padding: EdgeInsets.symmetric(vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle(color: AppColor.textSecondary, fontSize: 14), ), Text( value, style: TextStyle( color: AppColor.textPrimary, fontSize: 14, fontWeight: FontWeight.w600, ), ), ], ), ); } }