import 'dart:developer'; import 'package:enaklo_pos/core/components/flushbar.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart'; import 'package:enaklo_pos/presentation/payment/pages/payment_page.dart'; import 'package:flutter/material.dart'; class AppColorSplitBill { static const Color primary = Color(0xff36175e); static const Color background = Color(0xfff8f9fa); static const Color cardBackground = Colors.white; static const Color textPrimary = Color(0xff2d3436); static const Color textSecondary = Color(0xff636e72); static const Color success = Color(0xff00b894); static const Color border = Color(0xffddd); } class SplitBillPage extends StatefulWidget { final Order order; const SplitBillPage({super.key, required this.order}); @override State createState() => _SplitBillPageState(); } class _SplitBillPageState extends State { int selectedSplitType = 0; // 0 = Per Product, 1 = Per Amount // Per Product Split Data Map selectedProducts = {}; // {itemId: quantity} // Per Amount Split Data TextEditingController amountController = TextEditingController(); int splitAmount = 0; List getOrderItemPending() => widget.order.orderItems ?.where((item) => item.status == "pending") .toList() ?? []; @override void dispose() { amountController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColorSplitBill.background, body: Row( children: [ // Left Panel - Bill Details Expanded( flex: 2, child: Container( color: AppColorSplitBill.cardBackground, padding: EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Ringkasan Pesanan', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColorSplitBill.textPrimary, ), ), SizedBox(height: 8), Text( 'Order #${widget.order.orderNumber}', style: TextStyle( fontSize: 16, color: AppColorSplitBill.textSecondary, ), ), SizedBox(height: 24), Expanded( child: ListView.builder( itemCount: getOrderItemPending().length, itemBuilder: (context, index) { return _buildOrderItem(getOrderItemPending()[index]); }, ), ), Container( width: double.infinity, height: 1, color: AppColorSplitBill.border, margin: EdgeInsets.symmetric(vertical: 16), ), if (widget.order.subtotal != widget.order.totalAmount) ...[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Subtotal', style: TextStyle( fontSize: 16, color: AppColorSplitBill.textSecondary, ), ), Text( 'Rp ${_formatCurrency(widget.order.subtotal ?? 0)}', style: TextStyle( fontSize: 16, color: AppColorSplitBill.textSecondary, ), ), ], ), if ((widget.order.taxAmount ?? 0) > 0) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Pajak', style: TextStyle( fontSize: 16, color: AppColorSplitBill.textSecondary, ), ), Text( 'Rp ${_formatCurrency(widget.order.taxAmount ?? 0)}', style: TextStyle( fontSize: 16, color: AppColorSplitBill.textSecondary, ), ), ], ), if ((widget.order.discountAmount ?? 0) > 0) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Diskon', style: TextStyle( fontSize: 16, color: AppColorSplitBill.success, ), ), Text( '- Rp ${_formatCurrency(widget.order.discountAmount ?? 0)}', style: TextStyle( fontSize: 16, color: AppColorSplitBill.success, ), ), ], ), SizedBox(height: 8), ], Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Total Pembayaran', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: AppColorSplitBill.textPrimary, ), ), Text( 'Rp ${_formatCurrency(widget.order.totalAmount ?? 0)}', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: AppColorSplitBill.primary, ), ), ], ), ], ), ), ), // Right Panel - Split Options Expanded( flex: 3, child: Container( padding: EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Bagi Bill', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColorSplitBill.textPrimary, ), ), SizedBox(height: 24), // Split Type Selection Row( children: [ _buildSplitTypeButton('Per Produk', 0), SizedBox(width: 16), _buildSplitTypeButton('Per Jumlah', 1), ], ), SizedBox(height: 32), // Split Content Expanded( child: selectedSplitType == 0 ? _buildPerProductSplit() : _buildPerAmountSplit(), ), SizedBox(height: 24), // Action Buttons Row( children: [ Expanded( child: _buildActionButton( 'Batal', AppColorSplitBill.textSecondary, Colors.transparent, () => Navigator.pop(context), ), ), SizedBox(width: 16), Expanded( child: _buildActionButton( 'Konfirmasi Split', Colors.white, AppColorSplitBill.primary, () { _confirmSplit(); }, ), ), ], ), ], ), ), ), ], ), ); } Widget _buildOrderItem(OrderItem item) { return Container( padding: EdgeInsets.symmetric(vertical: 12), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.productName ?? '', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), ), if (item.productVariantName != null && item.productVariantName!.isNotEmpty) Text( item.productVariantName!, style: TextStyle( fontSize: 14, color: AppColorSplitBill.textSecondary, fontStyle: FontStyle.italic, ), ), Text( 'Qty: ${item.quantity} x Rp ${_formatCurrency(item.unitPrice ?? 0)}', style: TextStyle( fontSize: 14, color: AppColorSplitBill.textSecondary, ), ), ], ), ), Text( 'Rp ${_formatCurrency(item.totalPrice ?? 0)}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), ), ], ), ); } Widget _buildSplitTypeButton(String title, int type) { bool isSelected = selectedSplitType == type; return GestureDetector( onTap: () { setState(() { selectedSplitType = type; }); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), decoration: BoxDecoration( color: isSelected ? AppColorSplitBill.primary : Colors.transparent, border: Border.all( color: isSelected ? AppColorSplitBill.primary : AppColorSplitBill.border, width: 2, ), borderRadius: BorderRadius.circular(8), ), child: Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: isSelected ? Colors.white : AppColorSplitBill.textPrimary, ), ), ), ); } Widget _buildPerProductSplit() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Pilih Produk untuk Split', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColorSplitBill.textPrimary, ), ), SizedBox(height: 16), Expanded( child: Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: AppColorSplitBill.cardBackground, border: Border.all(color: AppColorSplitBill.border), borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Split Bill', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColorSplitBill.primary, ), ), SizedBox(height: 16), Expanded( child: ListView.builder( itemCount: getOrderItemPending().length, itemBuilder: (context, index) { return _buildProductSplitItem( getOrderItemPending()[index]); }, ), ), Container( width: double.infinity, height: 1, color: AppColorSplitBill.border, margin: EdgeInsets.symmetric(vertical: 12), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Total Split:', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), ), Text( 'Rp ${_formatCurrency(_calculateSplitTotal())}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColorSplitBill.primary, ), ), ], ), ], ), ), ), ], ); } Widget _buildProductSplitItem(OrderItem item) { int selectedQty = selectedProducts[item.id] ?? 0; int maxQty = item.quantity ?? 0; return Container( margin: EdgeInsets.only(bottom: 12), padding: EdgeInsets.all(12), decoration: BoxDecoration( color: selectedQty > 0 ? AppColorSplitBill.primary.withOpacity(0.1) : Colors.transparent, border: Border.all( color: selectedQty > 0 ? AppColorSplitBill.primary : AppColorSplitBill.border, ), borderRadius: BorderRadius.circular(6), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.productName ?? '', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), ), if (item.productVariantName != null && item.productVariantName!.isNotEmpty) Text( item.productVariantName!, style: TextStyle( fontSize: 12, color: AppColorSplitBill.textSecondary, fontStyle: FontStyle.italic, ), ), Text( 'Rp ${_formatCurrency(item.unitPrice ?? 0)} per item', style: TextStyle( fontSize: 12, color: AppColorSplitBill.textSecondary, ), ), ], ), ), Row( children: [ GestureDetector( onTap: () { if (selectedQty > 0) { setState(() { selectedProducts[item.id!] = selectedQty - 1; if (selectedProducts[item.id!] == 0) { selectedProducts.remove(item.id); } }); } }, child: Container( width: 32, height: 32, decoration: BoxDecoration( color: selectedQty > 0 ? AppColorSplitBill.primary : AppColorSplitBill.border, borderRadius: BorderRadius.circular(4), ), child: Icon( Icons.remove, size: 16, color: selectedQty > 0 ? Colors.white : AppColorSplitBill.textSecondary, ), ), ), Container( width: 40, height: 32, margin: EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( border: Border.all(color: AppColorSplitBill.border), borderRadius: BorderRadius.circular(4), ), child: Center( child: Text( '$selectedQty', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: AppColorSplitBill.textPrimary, ), ), ), ), GestureDetector( onTap: () { if (selectedQty < maxQty) { setState(() { selectedProducts[item.id!] = selectedQty + 1; }); } }, child: Container( width: 32, height: 32, decoration: BoxDecoration( color: selectedQty < maxQty ? AppColorSplitBill.primary : AppColorSplitBill.border, borderRadius: BorderRadius.circular(4), ), child: Icon( Icons.add, size: 16, color: selectedQty < maxQty ? Colors.white : AppColorSplitBill.textSecondary, ), ), ), ], ), ], ), ); } Widget _buildPerAmountSplit() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Masukkan Jumlah yang Akan Dibayar', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColorSplitBill.textPrimary, ), ), SizedBox(height: 16), Expanded( child: Column( children: [ Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: AppColorSplitBill.cardBackground, border: Border.all(color: AppColorSplitBill.border), borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Split Bill', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColorSplitBill.primary, ), ), SizedBox(height: 16), Text( 'Jumlah yang akan dibayar:', style: TextStyle( fontSize: 14, color: AppColorSplitBill.textSecondary, ), ), SizedBox(height: 8), Container( decoration: BoxDecoration( border: Border.all(color: AppColorSplitBill.border), borderRadius: BorderRadius.circular(8), ), child: TextField( controller: amountController, keyboardType: TextInputType.number, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), onChanged: (value) { setState(() { splitAmount = int.tryParse(value) ?? 0; }); }, decoration: InputDecoration( hintText: '0', prefixText: 'Rp ', prefixStyle: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), border: InputBorder.none, contentPadding: EdgeInsets.all(16), ), ), ), SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Total yang dibayar:', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColorSplitBill.textPrimary, ), ), Text( 'Rp ${_formatCurrency(splitAmount)}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColorSplitBill.primary, ), ), ], ), SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Sisa bill:', style: TextStyle( fontSize: 14, color: AppColorSplitBill.textSecondary, ), ), Text( 'Rp ${_formatCurrency((widget.order.totalAmount ?? 0) - splitAmount)}', style: TextStyle( fontSize: 14, color: AppColorSplitBill.textSecondary, ), ), ], ), ], ), ), ], ), ), ], ); } Widget _buildActionButton( String text, Color textColor, Color bgColor, VoidCallback onTap) { return GestureDetector( onTap: onTap, child: Container( height: 50, decoration: BoxDecoration( color: bgColor, border: bgColor == Colors.transparent ? Border.all(color: AppColorSplitBill.border) : null, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( text, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: textColor, ), ), ), ), ); } int _calculateSplitTotal() { int total = 0; selectedProducts.forEach((itemId, quantity) { OrderItem? item = getOrderItemPending() .firstWhere((item) => item.id == itemId, orElse: () => OrderItem()); if (item.unitPrice != null) { total += (item.unitPrice! * quantity); } }); return total; } String _formatCurrency(int amount) { return amount.toString().replaceAllMapped( RegExp(r'(\d)(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]}.', ); } void _confirmSplit() { if (selectedSplitType == 0) { // Per Product Split int splitTotal = _calculateSplitTotal(); if (splitTotal > 0) { // Create a new Order object with only the selected products for split List splitItems = []; selectedProducts.forEach((itemId, quantity) { OrderItem? originalItem = getOrderItemPending().firstWhere( (item) => item.id == itemId, orElse: () => OrderItem()); // ignore: unnecessary_null_comparison if (originalItem != null && originalItem.id != null) { // Create a copy of the item with the selected quantity OrderItem splitItem = OrderItem( id: originalItem.id, productName: originalItem.productName, productVariantName: originalItem.productVariantName, quantity: quantity, unitPrice: originalItem.unitPrice, totalPrice: (originalItem.unitPrice ?? 0) * quantity, status: originalItem.status, ); splitItems.add(splitItem); } }); // Create split order object Order splitOrder = Order( id: widget.order.id, orderNumber: widget.order.orderNumber, orderItems: splitItems, subtotal: splitTotal, totalAmount: splitTotal, taxAmount: 0, // You might want to calculate proportional tax discountAmount: 0, // You might want to calculate proportional discount ); log("Split Order: ${splitItems.length}"); // Navigate to PaymentPage with the split order context.push(PaymentPage(order: splitOrder)); } else { AppFlushbar.showError(context, "Pilih minimal satu produk untuk split"); } } else { // Per Amount Split int totalAmount = widget.order.totalAmount ?? 0; if (splitAmount > 0 && splitAmount <= totalAmount) { // Create split order object with the specified amount Order splitOrder = Order( id: widget.order.id, orderNumber: widget.order.orderNumber, orderItems: getOrderItemPending(), // Keep all items for reference subtotal: splitAmount, totalAmount: splitAmount, taxAmount: 0, // You might want to calculate proportional values discountAmount: 0, ); // Navigate to PaymentPage with the split order context.push(PaymentPage(order: splitOrder)); } else if (splitAmount > totalAmount) { AppFlushbar.showError( context, "Jumlah split tidak boleh melebihi total bill"); } else { AppFlushbar.showError(context, "Pilih minimal satu produk untuk split"); } } } }