/// Cart Page /// /// Shopping cart screen with items, warehouse selection, discount code, /// and order summary matching the HTML design. library; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/core/router/app_router.dart'; import 'package:worker/core/theme/colors.dart'; import 'package:worker/core/theme/typography.dart'; import 'package:worker/features/cart/presentation/providers/cart_provider.dart'; import 'package:worker/features/cart/presentation/providers/cart_state.dart'; import 'package:worker/features/cart/presentation/widgets/cart_item_widget.dart'; /// Cart Page /// /// Features: /// - AppBar with back, title (with count), and clear cart button /// - Warehouse selection dropdown /// - Cart items list /// - Discount code input with apply button /// - Order summary with breakdown /// - Checkout button class CartPage extends ConsumerStatefulWidget { const CartPage({super.key}); @override ConsumerState createState() => _CartPageState(); } class _CartPageState extends ConsumerState { final TextEditingController _discountController = TextEditingController(); @override void dispose() { _discountController.dispose(); super.dispose(); } void _clearCart() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Xóa giỏ hàng'), content: const Text('Bạn có chắc chắn muốn xóa toàn bộ giỏ hàng?'), actions: [ TextButton( onPressed: () => context.pop(), child: const Text('Hủy'), ), ElevatedButton( onPressed: () { ref.read(cartProvider.notifier).clearCart(); context.pop(); context.pop(); // Also go back from cart page }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.danger, ), child: const Text('Xóa'), ), ], ), ); } @override Widget build(BuildContext context) { final cartState = ref.watch(cartProvider); final itemCount = cartState.itemCount; final currencyFormatter = NumberFormat.currency( locale: 'vi_VN', symbol: 'đ', decimalDigits: 0, ); return Scaffold( backgroundColor: const Color(0xFFF4F6F8), appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => context.pop(), ), title: Text('Giỏ hàng ($itemCount)', style: const TextStyle(color: Colors.black)), elevation: AppBarSpecs.elevation, backgroundColor: AppColors.white, foregroundColor: AppColors.grey900, centerTitle: false, actions: [ if (cartState.isNotEmpty) IconButton( icon: const Icon(Icons.delete_outline, color: Colors.black), onPressed: _clearCart, tooltip: 'Xóa giỏ hàng', ), const SizedBox(width: AppSpacing.sm), ], ), body: cartState.isEmpty ? _buildEmptyCart() : SingleChildScrollView( child: Column( children: [ const SizedBox(height: 8), // Warehouse Selection _buildWarehouseSelection(cartState.selectedWarehouse), // Cart Items ...cartState.items.map((item) => CartItemWidget(item: item)), const SizedBox(height: 8), // Discount Code _buildDiscountCodeSection(cartState), // Order Summary _buildOrderSummary(cartState, currencyFormatter), const SizedBox(height: 16), // Checkout Button _buildCheckoutButton(cartState), const SizedBox(height: 24), ], ), ), ); } /// Build empty cart state Widget _buildEmptyCart() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.shopping_cart_outlined, size: 80, color: AppColors.grey500.withValues(alpha: 0.5), ), const SizedBox(height: 16), Text( 'Giỏ hàng trống', style: AppTypography.headlineMedium.copyWith( color: AppColors.grey500, ), ), const SizedBox(height: 8), Text( 'Hãy thêm sản phẩm vào giỏ hàng', style: AppTypography.bodyMedium.copyWith( color: AppColors.grey500, ), ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: () => context.go(RouteNames.products), icon: const Icon(Icons.shopping_bag_outlined), label: const Text('Xem sản phẩm'), ), ], ), ); } /// Build warehouse selection card Widget _buildWarehouseSelection(String selectedWarehouse) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Kho xuất hàng', style: AppTypography.labelLarge.copyWith( fontWeight: FontWeight.w600, color: AppColors.grey900, ), ), const SizedBox(height: 8), DropdownButtonFormField( initialValue: selectedWarehouse, decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: AppColors.grey100), ), ), items: const [ DropdownMenuItem( value: 'Kho Hà Nội - Nguyễn Trãi', child: Text('Kho Hà Nội - Nguyễn Trãi'), ), DropdownMenuItem( value: 'Kho TP.HCM - Quận 7', child: Text('Kho TP.HCM - Quận 7'), ), DropdownMenuItem( value: 'Kho Đà Nẵng - Sơn Trà', child: Text('Kho Đà Nẵng - Sơn Trà'), ), ], onChanged: (value) { if (value != null) { ref.read(cartProvider.notifier).selectWarehouse(value); } }, ), ], ), ); } /// Build discount code section Widget _buildDiscountCodeSection(CartState cartState) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Mã giảm giá', style: AppTypography.labelLarge.copyWith( fontWeight: FontWeight.w600, color: AppColors.grey900, ), ), const SizedBox(height: 8), Row( children: [ Expanded( child: TextField( controller: _discountController, decoration: InputDecoration( hintText: 'Nhập mã giảm giá', contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 12, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: AppColors.grey100), ), ), ), ), const SizedBox(width: 8), ElevatedButton( onPressed: () { if (_discountController.text.isNotEmpty) { ref.read(cartProvider.notifier).applyDiscountCode( _discountController.text, ); } }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12, ), ), child: const Text('Áp dụng'), ), ], ), // Success message for member discount if (cartState.memberTier.isNotEmpty) Padding( padding: const EdgeInsets.only(top: 8), child: Row( children: [ const Icon( Icons.check_circle, color: AppColors.success, size: 16, ), const SizedBox(width: 4), Text( 'Bạn được giảm ${cartState.memberDiscountPercent.toStringAsFixed(0)}% (hạng ${cartState.memberTier})', style: AppTypography.bodySmall.copyWith( color: AppColors.success, ), ), ], ), ), ], ), ); } /// Build order summary section Widget _buildOrderSummary(CartState cartState, NumberFormat currencyFormatter) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Thông tin đơn hàng', style: AppTypography.titleMedium.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), // Subtotal Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Tạm tính (${cartState.totalQuantity.toStringAsFixed(0)} ${cartState.items.firstOrNull?.product.unit ?? 'm²'})', style: AppTypography.bodyMedium, ), Text( currencyFormatter.format(cartState.subtotal), style: AppTypography.bodyMedium, ), ], ), const SizedBox(height: 12), // Member Discount if (cartState.memberDiscount > 0) Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Giảm giá ${cartState.memberTier} (-${cartState.memberDiscountPercent.toStringAsFixed(0)}%)', style: AppTypography.bodyMedium, ), Text( '-${currencyFormatter.format(cartState.memberDiscount)}', style: AppTypography.bodyMedium.copyWith( color: AppColors.success, ), ), ], ), ), // Shipping Fee Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Phí vận chuyển', style: AppTypography.bodyMedium, ), Text( cartState.shippingFee > 0 ? currencyFormatter.format(cartState.shippingFee) : 'Miễn phí', style: AppTypography.bodyMedium, ), ], ), const Divider(height: 24), // Total Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Tổng cộng', style: AppTypography.titleMedium.copyWith( fontWeight: FontWeight.bold, ), ), Text( currencyFormatter.format(cartState.total), style: AppTypography.headlineSmall.copyWith( color: AppColors.primaryBlue, fontWeight: FontWeight.bold, ), ), ], ), ], ), ); } /// Build checkout button Widget _buildCheckoutButton(CartState cartState) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: SizedBox( width: double.infinity, height: 48, child: ElevatedButton( onPressed: cartState.isNotEmpty ? () { // TODO: Navigate to checkout page when implemented ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Checkout page chưa được triển khai'), ), ); } : null, child: const Text( 'Tiến hành đặt hàng', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), ), ); } }