2025-08-04 12:38:33 +07:00

408 lines
16 KiB
Dart

import 'dart:developer';
import 'package:enaklo_pos/core/components/buttons.dart';
import 'package:enaklo_pos/core/components/custom_modal_dialog.dart';
import 'package:enaklo_pos/core/components/flushbar.dart';
import 'package:enaklo_pos/core/components/spaces.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 PaymentDialog extends StatefulWidget {
final Order order;
const PaymentDialog({super.key, required this.order});
@override
State<PaymentDialog> createState() => _PaymentDialogState();
}
class _PaymentDialogState extends State<PaymentDialog> {
PaymentMethod? selectedPaymentMethod;
final totalPriceController = TextEditingController();
int priceValue = 0;
int uangPas = 0;
int uangPas2 = 0;
int uangPas3 = 0;
init() {
setState(() {
uangPas = widget.order.totalAmount ?? 0;
uangPas2 = 50000;
uangPas3 = 100000;
});
}
@override
void initState() {
super.initState();
context
.read<PaymentMethodsBloc>()
.add(PaymentMethodsEvent.fetchPaymentMethods());
init();
}
@override
void dispose() {
super.dispose();
totalPriceController.dispose();
}
@override
Widget build(BuildContext context) {
return CustomModalDialog(
title: 'Pembayaran',
subtitle: 'Silahkan lakukan pembayaran',
minWidth: context.deviceWidth * 0.6,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: AppColors.grey,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Metode Pembayaran',
style: TextStyle(
color: AppColors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(12.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('No. Pesanan'),
Text(
widget.order.orderNumber ?? "",
style: const TextStyle(fontWeight: FontWeight.bold),
),
],
),
const SpaceHeight(6),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Tagihan'),
Text(
(widget.order.totalAmount ?? 0).currencyFormatRpV2,
style: const TextStyle(fontWeight: FontWeight.bold),
),
],
),
],
),
),
Container(
padding: const EdgeInsets.all(16),
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: AppColors.grey,
width: 1.0,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Metode Pembayaran',
style: TextStyle(
color: AppColors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(12.0),
BlocBuilder<PaymentMethodsBloc, PaymentMethodsState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () => const Center(
child: CircularProgressIndicator(),
),
loading: () => const Center(
child: Column(
children: [
CircularProgressIndicator(),
SizedBox(height: 8.0),
Text('Loading payment methods...'),
],
),
),
error: (message) => Column(
children: [
Center(
child:
Text('Error loading payment methods: $message'),
),
const SpaceHeight(16.0),
Button.filled(
onPressed: () {
context.read<PaymentMethodsBloc>().add(
PaymentMethodsEvent.fetchPaymentMethods());
},
label: 'Retry',
),
],
),
loaded: (paymentMethods) {
log("Loaded ${paymentMethods.length} payment methods");
paymentMethods.forEach((method) {
log("Payment method: ${method.name} (ID: ${method.id})");
});
if (paymentMethods.isEmpty) {
return Column(
children: [
const Center(
child: Text('No payment methods available'),
),
const SpaceHeight(16.0),
Button.filled(
onPressed: () {
context.read<PaymentMethodsBloc>().add(
PaymentMethodsEvent
.fetchPaymentMethods());
},
label: 'Retry',
),
],
);
}
return Wrap(
spacing: 12.0,
runSpacing: 8.0,
children: paymentMethods.map((method) {
final isSelected =
selectedPaymentMethod?.id == method.id;
return GestureDetector(
onTap: () {
setState(() {
selectedPaymentMethod = method;
});
},
child: Container(
height: 60,
width: 80,
alignment: Alignment.center,
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: isSelected
? AppColors.primary
: AppColors.white,
border: Border.all(
color: AppColors.primary,
width: 1.0,
),
borderRadius: BorderRadius.circular(8.0),
),
child: Text(
method.name ?? "",
style: TextStyle(
color: isSelected
? AppColors.white
: AppColors.primary,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
);
}).toList(),
);
},
);
},
),
],
),
),
if (selectedPaymentMethod?.type == "cash")
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: AppColors.grey,
width: 1.0,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Total Bayar',
style: TextStyle(
color: AppColors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(8.0),
TextFormField(
controller: totalPriceController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
hintText: 'Total harga',
),
onChanged: (value) {
priceValue = value.toIntegerFromText;
final int newValue = value.toIntegerFromText;
totalPriceController.text = newValue.currencyFormatRp;
totalPriceController.selection =
TextSelection.fromPosition(TextPosition(
offset: totalPriceController.text.length));
},
),
const SpaceHeight(20.0),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Button.outlined(
width: 150.0,
onPressed: () {
totalPriceController.text =
uangPas.toString().currencyFormatRpV2;
priceValue = uangPas;
},
label: 'UANG PAS',
),
const SpaceWidth(20.0),
Button.outlined(
width: 150.0,
onPressed: () {
totalPriceController.text =
uangPas2.toString().currencyFormatRpV2;
priceValue = uangPas2;
},
label: uangPas2.toString().currencyFormatRpV2,
),
const SpaceWidth(20.0),
Button.outlined(
width: 150.0,
onPressed: () {
totalPriceController.text =
uangPas3.toString().currencyFormatRpV2;
priceValue = uangPas3;
},
label: uangPas3.toString().currencyFormatRpV2,
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 24,
horizontal: 16,
),
child: BlocListener<PaymentFormBloc, PaymentFormState>(
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,
));
},
error: (message) {
AppFlushbar.showError(context, message);
},
);
},
child: BlocBuilder<PaymentFormBloc, PaymentFormState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () => Button.filled(
onPressed: () {
if (selectedPaymentMethod == null) {
AppFlushbar.showError(context,
'Pilih metode pembayaran terlebih dahulu');
return;
}
if (selectedPaymentMethod?.type == "cash") {
if (priceValue == 0) {
AppFlushbar.showError(
context, 'Total bayar tidak boleh 0');
return;
}
}
final itemPending = widget.order.orderItems
?.where((item) => item.status == "pending")
.toList();
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<PaymentFormBloc>()
.add(PaymentFormEvent.create(request));
},
label: 'Bayar',
),
loading: () => Center(
child: const CircularProgressIndicator(),
),
);
},
),
),
),
],
),
);
}
}