import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../application/checkout/checkout_form/checkout_form_bloc.dart'; import '../../../common/extension/extension.dart'; import '../../../common/theme/theme.dart'; import '../../../domain/product/product.dart'; import '../dialog/dialog.dart'; import '../image/image.dart'; import '../spaces/space.dart'; class ProductCard extends StatelessWidget { final Product product; const ProductCard({super.key, required this.product}); @override Widget build(BuildContext context) { return GestureDetector( onTap: () { if (product.isActive != true) return; if (product.variants.isNotEmpty) { showDialog( context: context, builder: (context) => VariantDialog(product: product), ); return; } // Produk timbangan tidak bisa langsung masuk keranjang — kasir harus // menimbang dulu, dan tiap penimbangan jadi barisnya sendiri. if (product.isSoldByWeight) { final bloc = context.read(); showDialog( context: context, builder: (context) => WeightInputDialog( product: product, onSubmit: (weight) => bloc.add( CheckoutFormEvent.addWeightedItem(product, null, weight), ), ), ); return; } context.read().add( CheckoutFormEvent.addItem(product, null), ); }, child: Container( decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(8.0), border: Border.all(color: AppColor.disabled), ), child: Stack( children: [ Padding( padding: const EdgeInsets.all(4.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8.0)), child: product.imageUrl == "" ? Container( width: double.infinity, height: 120, decoration: BoxDecoration( color: AppColor.disabled.withOpacity(0.4), ), child: const Icon( Icons.image, color: AppColor.textSecondary, ), ) : AppNetworkImage( url: product.imageUrl, fit: BoxFit.fill, width: double.infinity, height: 140, ), ), const Spacer(), Text( product.name, style: AppStyle.md.copyWith(fontWeight: FontWeight.w700), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SpaceHeight(4), Align( alignment: Alignment.center, child: Text( product.isSoldByWeight ? '${product.price.currencyFormatRp} ${product.priceUnitLabel}' .trim() : product.price.currencyFormatRp, textAlign: TextAlign.center, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 12, ), ), ), const SpaceHeight(4), ], ), ), BlocBuilder( builder: (context, state) { final lines = state.items .where((item) => item.product.id == product.id) .toList(); if (lines.isEmpty) return const SizedBox.shrink(); // Untuk produk timbangan, jumlah baris tidak berarti apa-apa // (selalu 1 per penimbangan) — yang informatif adalah total // berat yang sudah masuk keranjang. final label = product.isSoldByWeight ? '${lines.fold(0, (sum, item) => sum + (item.weight ?? 0)).weightFormat} ${product.unitLabel}' .trim() : lines .fold(0, (sum, item) => sum + item.quantity) .toString(); return Positioned( top: 4, right: 4, child: Container( constraints: const BoxConstraints(minWidth: 40), height: 40, padding: const EdgeInsets.symmetric(horizontal: 6), decoration: const BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(9.0)), color: AppColor.primary, ), child: Center( child: Text( label, style: TextStyle( color: Colors.white, fontSize: product.isSoldByWeight ? 13 : 20, fontWeight: FontWeight.bold, ), ), ), ), ); }, ), if (product.isActive == false) Container( width: double.infinity, decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(8.0)), color: AppColor.disabled.withOpacity(0.5), ), ), ], ), ), ); } }