import 'package:enaklo_pos/core/components/buttons.dart'; import 'package:enaklo_pos/core/components/flushbar.dart'; import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/data/models/request/payment_request.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart'; import 'package:enaklo_pos/data/models/response/payment_methods_response_model.dart'; import 'package:enaklo_pos/data/models/response/product_response_model.dart'; import 'package:enaklo_pos/presentation/home/bloc/payment_methods/payment_methods_bloc.dart'; import 'package:enaklo_pos/presentation/home/models/product_quantity.dart'; import 'package:enaklo_pos/presentation/sales/blocs/payment_form/payment_form_bloc.dart'; import 'package:enaklo_pos/presentation/success/pages/success_payment_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class PaymentPage extends StatefulWidget { final Order order; final bool isSplit; final String? splitType; const PaymentPage({ super.key, required this.order, this.isSplit = false, this.splitType, }); @override State createState() => _PaymentPageState(); } class _PaymentPageState extends State { PaymentMethod? selectedPaymentMethod; final totalPriceController = TextEditingController(); int priceValue = 0; late int uangPas; final int uangPas2 = 50000; final int uangPas3 = 100000; List getOrderItemPending() { final itemPending = widget.order.orderItems ?.where((item) => item.status == "pending") .toList(); return itemPending ?? []; } @override void initState() { super.initState(); uangPas = widget.order.totalAmount ?? 0; totalPriceController.text = uangPas.currencyFormatRpV2; priceValue = uangPas; context .read() .add(PaymentMethodsEvent.fetchPaymentMethods()); } @override void dispose() { totalPriceController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final totalAmount = widget.order.totalAmount ?? 0; return Scaffold( backgroundColor: AppColors.background, appBar: AppBar( backgroundColor: AppColors.primary, title: const Text( 'Pembayaran', style: TextStyle(color: AppColors.white), ), leading: IconButton( onPressed: () => context.pop(), icon: Icon( Icons.arrow_back, color: AppColors.white, ), ), ), body: LayoutBuilder( builder: (context, constraints) { final isWide = constraints.maxWidth > 800; return Padding( padding: const EdgeInsets.all(16), child: isWide ? Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(flex: 3, child: _buildOrderDetail()), const SizedBox(width: 24), Expanded(flex: 2, child: _buildPaymentForm(totalAmount)), ], ) : SingleChildScrollView( child: Column( children: [ _buildOrderDetail(), const SizedBox(height: 24), _buildPaymentForm(totalAmount), ], ), ), ); }, ), ); } Widget _buildOrderDetail() { final order = widget.order; final items = order.orderItems ?? []; return Card( elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), color: AppColors.white, child: Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Detail Order', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColors.primary)), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('No. Pesanan', style: TextStyle(fontWeight: FontWeight.w600)), Text(order.orderNumber ?? '-', style: const TextStyle(fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 8), Divider(color: AppColors.grey), const SizedBox(height: 8), Expanded( child: items.isEmpty ? const Center(child: Text('Tidak ada item')) : ListView.separated( shrinkWrap: true, itemCount: getOrderItemPending().length, separatorBuilder: (_, __) => Divider(color: AppColors.grey.withOpacity(0.5)), itemBuilder: (context, index) { final item = getOrderItemPending()[index]; return ListTile( contentPadding: EdgeInsets.zero, title: Text(item.productName ?? '-'), subtitle: Text( 'Qty: ${item.quantity ?? 0} | ${item.productVariantName ?? ''}'), trailing: Text( (item.totalPrice ?? 0).currencyFormatRpV2, style: const TextStyle(fontWeight: FontWeight.bold)), ); }, ), ), Divider(color: AppColors.grey), _buildSummaryRow('Subtotal', order.subtotal ?? 0), _buildSummaryRow('Pajak', order.taxAmount ?? 0), _buildSummaryRow('Diskon', order.discountAmount ?? 0), Divider(thickness: 2, color: AppColors.primary), _buildSummaryRow('Total', order.totalAmount ?? 0, isTotal: true, color: AppColors.primary), ], ), ), ); } Widget _buildSummaryRow(String label, int amount, {bool isTotal = false, Color? color}) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: TextStyle( fontWeight: isTotal ? FontWeight.bold : FontWeight.normal, fontSize: isTotal ? 18 : 14, color: color ?? Colors.black)), Text(amount.currencyFormatRpV2, style: TextStyle( fontWeight: isTotal ? FontWeight.bold : FontWeight.normal, fontSize: isTotal ? 18 : 14, color: color ?? Colors.black)), ], ), ); } Widget _buildPaymentForm(int totalAmount) { return Card( elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), color: AppColors.white, child: Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('Pembayaran', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColors.primary)), Expanded( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 24), const Text('Metode Pembayaran', style: TextStyle(fontWeight: FontWeight.w600)), const SizedBox(height: 12), BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center(child: CircularProgressIndicator()), loading: () => const Center( child: Column( children: [ CircularProgressIndicator(), SizedBox(height: 8), Text('Loading metode pembayaran...'), ], ), ), error: (message) => Column( children: [ Text('Gagal memuat metode pembayaran: $message'), const SizedBox(height: 16), ElevatedButton( onPressed: () { context.read().add( PaymentMethodsEvent .fetchPaymentMethods()); }, child: const Text('Coba Lagi'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, ), ), ], ), loaded: (methods) { if (methods.isEmpty) { return Column( children: [ const Text( 'Tidak ada metode pembayaran tersedia'), const SizedBox(height: 16), ElevatedButton( onPressed: () { context.read().add( PaymentMethodsEvent .fetchPaymentMethods()); }, child: const Text('Coba Lagi'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, ), ), ], ); } return Wrap( spacing: 12, runSpacing: 12, children: methods.map((method) { final isSelected = selectedPaymentMethod?.id == method.id; return ChoiceChip( label: Text(method.name ?? ''), selected: isSelected, onSelected: (_) { setState(() { selectedPaymentMethod = method; if (method.type != "cash") { totalPriceController.text = totalAmount.currencyFormatRpV2; priceValue = totalAmount; } }); }, selectedColor: AppColors.primary, backgroundColor: AppColors.white, labelStyle: TextStyle( color: isSelected ? AppColors.white : AppColors.primary, fontWeight: FontWeight.bold, ), shape: RoundedRectangleBorder( side: BorderSide(color: AppColors.primary), borderRadius: BorderRadius.circular(8), ), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ); }).toList(), ); }, ); }, ), const SizedBox(height: 24), if (selectedPaymentMethod?.type == "cash") ...[ const Text('Total Bayar', style: TextStyle(fontWeight: FontWeight.w600)), const SizedBox(height: 8), TextFormField( controller: totalPriceController, keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8)), hintText: 'Masukkan nominal bayar', ), onChanged: (value) { final newValue = value.toIntegerFromText; setState(() { priceValue = newValue; totalPriceController.text = newValue.currencyFormatRp; totalPriceController.selection = TextSelection.fromPosition(TextPosition( offset: totalPriceController.text.length)); }); }, ), const SizedBox(height: 20), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ _quickAmountButton('UANG PAS', uangPas), const SizedBox(width: 16), _quickAmountButton( uangPas2.currencyFormatRpV2, uangPas2), const SizedBox(width: 16), _quickAmountButton( uangPas3.currencyFormatRpV2, uangPas3), ], ), ), ], const SizedBox(height: 32), ], ), ), ), BlocListener( listener: (context, state) { state.maybeWhen( orElse: () {}, success: (data) { context.pushReplacement(SuccessPaymentPage( productQuantity: widget.order.orderItems ?.map( (item) => ProductQuantity( product: Product( name: item.productName, price: item.unitPrice, ), quantity: item.quantity ?? 0, ), ) .toList() ?? [], payment: data, paymentMethod: selectedPaymentMethod?.name ?? '', nominalBayar: totalPriceController.text.toIntegerFromText, )); }, error: (message) { AppFlushbar.showError(context, message); }, ); }, child: BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => Button.filled(onPressed: _onPayPressed, label: "Bayar"), loading: () => const Center(child: CircularProgressIndicator()), ); }, ), ), ], ), ), ); } Widget _quickAmountButton(String label, int amount) { return OutlinedButton( onPressed: () { setState(() { totalPriceController.text = amount.currencyFormatRpV2; priceValue = amount; }); }, style: OutlinedButton.styleFrom( side: BorderSide(color: AppColors.primary), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), child: Text(label, style: TextStyle(color: AppColors.primary, fontWeight: FontWeight.bold)), ); } void _onPayPressed() { if (selectedPaymentMethod == null) { AppFlushbar.showError(context, 'Pilih metode pembayaran terlebih dahulu'); return; } if (selectedPaymentMethod?.type == "cash" && priceValue == 0) { AppFlushbar.showError(context, 'Total bayar tidak boleh 0'); return; } final itemPending = widget.order.orderItems ?.where((item) => item.status == "pending") .toList(); if (widget.isSplit == false) { final request = PaymentRequestModel( amount: widget.order.totalAmount ?? 0, orderId: widget.order.id, paymentMethodId: selectedPaymentMethod?.id, splitDescription: '', splitNumber: 1, splitTotal: 1, transactionId: '', paymentOrderItems: itemPending ?.map((item) => PaymentOrderItemModel( orderItemId: item.id, amount: item.totalPrice, )) .toList(), ); context.read().add(PaymentFormEvent.create(request)); } else { final request = PaymentSplitBillRequest( amount: widget.order.totalAmount ?? 0, customerId: '', items: itemPending ?.map((item) => SplitItem( orderItemId: item.id ?? "", quantity: item.quantity ?? 0, )) .toList() ?? [], orderId: widget.order.id ?? "", paymentMethodId: selectedPaymentMethod?.id ?? "", type: widget.splitType ?? "", ); context.read().add( PaymentFormEvent.createSplitBill(request), ); } } }