/// Cart State /// /// Immutable state class for cart management. library; import 'package:worker/features/products/domain/entities/product.dart'; /// Cart Item Data /// /// Represents a product in the cart with quantity. class CartItemData { final Product product; final double quantity; final double quantityConverted; // Rounded-up quantity for actual billing final int boxes; // Number of tiles/boxes needed const CartItemData({ required this.product, required this.quantity, required this.quantityConverted, required this.boxes, }); /// Calculate line total using CONVERTED quantity (important for accurate billing) double get lineTotal => product.basePrice * quantityConverted; CartItemData copyWith({ Product? product, double? quantity, double? quantityConverted, int? boxes, }) { return CartItemData( product: product ?? this.product, quantity: quantity ?? this.quantity, quantityConverted: quantityConverted ?? this.quantityConverted, boxes: boxes ?? this.boxes, ); } } /// Cart State /// /// Represents the complete state of the shopping cart. class CartState { final List items; final Map selectedItems; // productId -> isSelected final String selectedWarehouse; final String? discountCode; final bool discountCodeApplied; final String memberTier; final double memberDiscountPercent; final double subtotal; final double memberDiscount; final double shippingFee; final double total; final bool isLoading; final String? errorMessage; const CartState({ required this.items, required this.selectedItems, required this.selectedWarehouse, this.discountCode, required this.discountCodeApplied, required this.memberTier, required this.memberDiscountPercent, required this.subtotal, required this.memberDiscount, required this.shippingFee, required this.total, this.isLoading = false, this.errorMessage, }); factory CartState.initial() { return const CartState( items: [], selectedItems: {}, selectedWarehouse: 'Kho Hà Nội - Nguyễn Trãi', discountCode: null, discountCodeApplied: false, memberTier: '', memberDiscountPercent: 0.0, subtotal: 0.0, memberDiscount: 0.0, shippingFee: 0.0, total: 0.0, ); } bool get isEmpty => items.isEmpty; bool get isNotEmpty => items.isNotEmpty; int get itemCount => items.length; /// Get total quantity across all items double get totalQuantity { return items.fold(0.0, (sum, item) => sum + item.quantity); } /// Get number of selected items int get selectedCount { return selectedItems.values.where((selected) => selected).length; } /// Check if all items are selected bool get isAllSelected { return items.isNotEmpty && selectedCount == items.length; } /// Get total of selected items only double get selectedTotal { double total = 0.0; for (final item in items) { if (selectedItems[item.product.productId] == true) { total += item.lineTotal; } } return total; } CartState copyWith({ List? items, Map? selectedItems, String? selectedWarehouse, String? discountCode, bool? discountCodeApplied, String? memberTier, double? memberDiscountPercent, double? subtotal, double? memberDiscount, double? shippingFee, double? total, bool? isLoading, String? errorMessage, }) { return CartState( items: items ?? this.items, selectedItems: selectedItems ?? this.selectedItems, selectedWarehouse: selectedWarehouse ?? this.selectedWarehouse, discountCode: discountCode ?? this.discountCode, discountCodeApplied: discountCodeApplied ?? this.discountCodeApplied, memberTier: memberTier ?? this.memberTier, memberDiscountPercent: memberDiscountPercent ?? this.memberDiscountPercent, subtotal: subtotal ?? this.subtotal, memberDiscount: memberDiscount ?? this.memberDiscount, shippingFee: shippingFee ?? this.shippingFee, total: total ?? this.total, isLoading: isLoading ?? this.isLoading, errorMessage: errorMessage, ); } }