2025-10-30 16:35:47 +07:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
|
|
|
|
|
|
import '../../../../application/payment/payment_form/payment_form_bloc.dart';
|
|
|
|
|
import '../../../../application/payment_method/payment_method_loader/payment_method_loader_bloc.dart';
|
|
|
|
|
import '../../../../common/extension/extension.dart';
|
|
|
|
|
import '../../../../common/theme/theme.dart';
|
2025-10-31 20:43:37 +07:00
|
|
|
import '../../../../common/types/split_type.dart';
|
2025-10-30 16:35:47 +07:00
|
|
|
import '../../../components/button/button.dart';
|
|
|
|
|
import '../../../components/card/payment_card.dart';
|
|
|
|
|
import '../../../components/error/payment_method_error_state_widget.dart';
|
|
|
|
|
import '../../../components/field/field.dart';
|
|
|
|
|
import '../../../components/loader/loader_with_text.dart';
|
|
|
|
|
import '../../../components/spaces/space.dart';
|
|
|
|
|
import '../../../components/toast/flushbar.dart';
|
|
|
|
|
|
|
|
|
|
class PaymentRightPanel extends StatefulWidget {
|
|
|
|
|
final PaymentFormState state;
|
2025-10-31 20:43:37 +07:00
|
|
|
final bool isSplit;
|
|
|
|
|
final SplitType splitType;
|
|
|
|
|
final String? customerId;
|
|
|
|
|
final String? customerName;
|
|
|
|
|
const PaymentRightPanel({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.state,
|
|
|
|
|
required this.isSplit,
|
|
|
|
|
this.customerId,
|
|
|
|
|
required this.splitType,
|
|
|
|
|
this.customerName,
|
|
|
|
|
});
|
2025-10-30 16:35:47 +07:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<PaymentRightPanel> createState() => _PaymentRightPanelState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _PaymentRightPanelState extends State<PaymentRightPanel> {
|
|
|
|
|
TextEditingController totalPriceController = TextEditingController();
|
|
|
|
|
|
|
|
|
|
int priceValue = 0;
|
|
|
|
|
int pasMoney1 = 0;
|
|
|
|
|
int pasMoney2 = 0;
|
|
|
|
|
int pasMoney3 = 0;
|
|
|
|
|
|
|
|
|
|
initMoney() {
|
|
|
|
|
setState(() {
|
|
|
|
|
priceValue = widget.state.order.totalAmount;
|
|
|
|
|
pasMoney1 = widget.state.order.totalAmount;
|
|
|
|
|
pasMoney2 = pasMoney1 ~/ 50000 * 50000 + 50000;
|
|
|
|
|
pasMoney3 = pasMoney1 ~/ 50000 * 50000 + 100000;
|
|
|
|
|
totalPriceController.text =
|
|
|
|
|
widget.state.order.totalAmount.currencyFormatRpV2;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
initMoney();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: AppColor.white,
|
|
|
|
|
borderRadius: BorderRadius.circular(12),
|
|
|
|
|
),
|
|
|
|
|
padding: EdgeInsets.all(16),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'Pembayaran',
|
|
|
|
|
style: AppStyle.h5.copyWith(
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
color: AppColor.primary,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
SpaceHeight(24),
|
|
|
|
|
Text(
|
|
|
|
|
'Metode Pembayaran',
|
|
|
|
|
style: AppStyle.md.copyWith(fontWeight: FontWeight.w600),
|
|
|
|
|
),
|
|
|
|
|
SpaceHeight(12),
|
|
|
|
|
BlocBuilder<
|
|
|
|
|
PaymentMethodLoaderBloc,
|
|
|
|
|
PaymentMethodLoaderState
|
|
|
|
|
>(
|
|
|
|
|
builder: (context, pmState) {
|
|
|
|
|
if (pmState.isFetching) {
|
|
|
|
|
return Center(child: LoaderWithText());
|
|
|
|
|
}
|
|
|
|
|
return pmState.failureOption.fold(
|
|
|
|
|
() => Wrap(
|
|
|
|
|
spacing: 12.0,
|
|
|
|
|
runSpacing: 8.0,
|
|
|
|
|
children: pmState.paymentMethods.map((item) {
|
|
|
|
|
// Set default selected payment method if none selected or if current selection is not in the list
|
|
|
|
|
if (widget.state.paymentMethod == null ||
|
|
|
|
|
!pmState.paymentMethods.any(
|
|
|
|
|
(method) =>
|
|
|
|
|
method.id ==
|
|
|
|
|
widget.state.paymentMethod?.id,
|
|
|
|
|
)) {
|
|
|
|
|
context.read<PaymentFormBloc>().add(
|
|
|
|
|
PaymentFormEvent.setPaymentMethod(
|
|
|
|
|
pmState.paymentMethods.first,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PaymentCard(
|
|
|
|
|
payment: item,
|
|
|
|
|
isSelected: widget.state.paymentMethod == item,
|
|
|
|
|
onSelected: (_) {
|
|
|
|
|
context.read<PaymentFormBloc>().add(
|
|
|
|
|
PaymentFormEvent.setPaymentMethod(item),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}).toList(),
|
|
|
|
|
),
|
|
|
|
|
(f) => PaymentMethodErrorStateWidget(failure: f),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
SpaceHeight(24),
|
|
|
|
|
if (widget.state.paymentMethod != null &&
|
|
|
|
|
widget.state.paymentMethod!.type == 'cash')
|
|
|
|
|
Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'Total Bayar',
|
|
|
|
|
style: AppStyle.lg.copyWith(
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SpaceHeight(8.0),
|
|
|
|
|
AppTextFormField(
|
|
|
|
|
label: 'Total Bayar',
|
|
|
|
|
showLabel: false,
|
|
|
|
|
keyboardType: TextInputType.number,
|
|
|
|
|
controller: totalPriceController,
|
|
|
|
|
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: [
|
|
|
|
|
AppElevatedButton.outlined(
|
|
|
|
|
width: 150.0,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
totalPriceController.text = pasMoney1
|
|
|
|
|
.toString()
|
|
|
|
|
.currencyFormatRpV2;
|
|
|
|
|
priceValue = pasMoney1;
|
|
|
|
|
},
|
|
|
|
|
label: 'UANG PAS',
|
|
|
|
|
),
|
|
|
|
|
const SpaceWidth(20.0),
|
|
|
|
|
AppElevatedButton.outlined(
|
|
|
|
|
width: 150.0,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
totalPriceController.text = pasMoney2
|
|
|
|
|
.toString()
|
|
|
|
|
.currencyFormatRpV2;
|
|
|
|
|
priceValue = pasMoney2;
|
|
|
|
|
},
|
|
|
|
|
label: pasMoney2.toString().currencyFormatRpV2,
|
|
|
|
|
),
|
|
|
|
|
const SpaceWidth(20.0),
|
|
|
|
|
AppElevatedButton.outlined(
|
|
|
|
|
width: 150.0,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
totalPriceController.text = pasMoney3
|
|
|
|
|
.toString()
|
|
|
|
|
.currencyFormatRpV2;
|
|
|
|
|
priceValue = pasMoney3;
|
|
|
|
|
},
|
|
|
|
|
label: pasMoney3.toString().currencyFormatRpV2,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
AppElevatedButton.filled(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
if (widget.state.paymentMethod == null) {
|
|
|
|
|
AppFlushbar.showError(
|
|
|
|
|
context,
|
|
|
|
|
'Pilih metode pembayaran terlebih dahulu',
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (widget.state.paymentMethod?.type == "cash" &&
|
|
|
|
|
priceValue == 0) {
|
|
|
|
|
AppFlushbar.showError(context, 'Total bayar tidak boleh 0');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!widget.state.isSubmitting) {
|
2025-10-31 20:43:37 +07:00
|
|
|
if (widget.isSplit) {
|
|
|
|
|
context.read<PaymentFormBloc>().add(
|
|
|
|
|
PaymentFormEvent.submittedSplitBill(
|
|
|
|
|
customerId: widget.customerId,
|
|
|
|
|
splitType: widget.splitType,
|
2025-11-01 03:24:39 +07:00
|
|
|
customerName: widget.customerName,
|
2025-10-31 20:43:37 +07:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
context.read<PaymentFormBloc>().add(
|
|
|
|
|
PaymentFormEvent.submitted(),
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-10-30 16:35:47 +07:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
label: 'Bayar',
|
|
|
|
|
isLoading: widget.state.isSubmitting,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|