split bill

This commit is contained in:
efrilm
2025-10-31 20:43:37 +07:00
parent 6b42cd86ff
commit 35f02e6b76
18 changed files with 1763 additions and 27 deletions
@@ -5,6 +5,7 @@ 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/theme/theme.dart';
import '../../../common/types/split_type.dart';
import '../../../domain/order/order.dart';
import '../../../injection.dart';
import '../../components/spaces/space.dart';
@@ -16,25 +17,61 @@ import 'widgets/payment_right_panel.dart';
@RoutePage()
class PaymentPage extends StatelessWidget implements AutoRouteWrapper {
final Order order;
const PaymentPage({super.key, required this.order});
final bool isSplit;
final SplitType splitType;
final String? customerId;
final String? customerName;
const PaymentPage({
super.key,
required this.order,
this.isSplit = false,
this.splitType = SplitType.unknown,
this.customerId,
this.customerName,
});
@override
Widget build(BuildContext context) {
return BlocListener<PaymentFormBloc, PaymentFormState>(
listenWhen: (p, c) => p.failureOrPayment != c.failureOrPayment,
listener: (context, state) {
state.failureOrPayment.fold(
() {},
(either) => either.fold(
(f) => AppFlushbar.showOrderFailureToast(context, f),
(data) {
if (context.mounted) {
context.router.replace(PaymentSuccessRoute(orderId: order.id));
}
},
),
);
},
return MultiBlocListener(
listeners: [
BlocListener<PaymentFormBloc, PaymentFormState>(
listenWhen: (p, c) => p.failureOrPayment != c.failureOrPayment,
listener: (context, state) {
state.failureOrPayment.fold(
() {},
(either) => either.fold(
(f) => AppFlushbar.showOrderFailureToast(context, f),
(data) {
if (context.mounted) {
context.router.replace(
PaymentSuccessRoute(orderId: order.id),
);
}
},
),
);
},
),
BlocListener<PaymentFormBloc, PaymentFormState>(
listenWhen: (p, c) =>
p.failureOrPaymentSplitBill != c.failureOrPaymentSplitBill,
listener: (context, state) {
state.failureOrPaymentSplitBill.fold(
() {},
(either) => either.fold(
(f) => AppFlushbar.showOrderFailureToast(context, f),
(data) {
if (context.mounted) {
context.router.replace(
PaymentSuccessRoute(orderId: order.id),
);
}
},
),
);
},
),
],
child: Scaffold(
backgroundColor: AppColor.background,
appBar: AppBar(
@@ -48,6 +85,24 @@ class PaymentPage extends StatelessWidget implements AutoRouteWrapper {
onPressed: () => context.router.maybePop(),
icon: Icon(Icons.arrow_back, color: AppColor.primary),
),
actions: [
if (isSplit)
Container(
padding: EdgeInsets.all(4),
margin: EdgeInsets.only(right: 8),
decoration: BoxDecoration(
border: Border.all(color: AppColor.primary),
borderRadius: BorderRadius.circular(8),
),
child: Text(
"Split Bill: ${splitType.toStringType()}",
style: AppStyle.sm.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.primary,
),
),
),
],
),
body: LayoutBuilder(
builder: (context, constraints) {
@@ -68,7 +123,13 @@ class PaymentPage extends StatelessWidget implements AutoRouteWrapper {
const SizedBox(width: 24),
Expanded(
flex: 2,
child: PaymentRightPanel(state: state),
child: PaymentRightPanel(
state: state,
isSplit: isSplit,
splitType: splitType,
customerId: customerId,
customerName: customerName,
),
),
],
)
@@ -77,7 +138,13 @@ class PaymentPage extends StatelessWidget implements AutoRouteWrapper {
children: [
PaymentLeftPanel(state: state),
const SpaceHeight(24),
PaymentRightPanel(state: state),
PaymentRightPanel(
state: state,
isSplit: isSplit,
splitType: splitType,
customerId: customerId,
customerName: customerName,
),
],
),
),
@@ -5,6 +5,7 @@ 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';
import '../../../../common/types/split_type.dart';
import '../../../components/button/button.dart';
import '../../../components/card/payment_card.dart';
import '../../../components/error/payment_method_error_state_widget.dart';
@@ -15,7 +16,18 @@ import '../../../components/toast/flushbar.dart';
class PaymentRightPanel extends StatefulWidget {
final PaymentFormState state;
const PaymentRightPanel({super.key, required this.state});
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,
});
@override
State<PaymentRightPanel> createState() => _PaymentRightPanelState();
@@ -211,9 +223,18 @@ class _PaymentRightPanelState extends State<PaymentRightPanel> {
}
if (!widget.state.isSubmitting) {
context.read<PaymentFormBloc>().add(
PaymentFormEvent.submitted(),
);
if (widget.isSplit) {
context.read<PaymentFormBloc>().add(
PaymentFormEvent.submittedSplitBill(
customerId: widget.customerId,
splitType: widget.splitType,
),
);
} else {
context.read<PaymentFormBloc>().add(
PaymentFormEvent.submitted(),
);
}
}
},
label: 'Bayar',
@@ -488,6 +488,12 @@ class _SplitBillRightPanelState extends State<SplitBillRightPanel> {
}
void _confirmSplit() {
if (widget.state.customerName == '' || widget.state.customer == null) {
AppFlushbar.showError(context, 'Nama Pelanggan harus diisi');
return;
}
if (widget.state.splitType.isItem) {
int splitTotal = widget.state.totalAmount;
if (splitTotal > 0) {
@@ -510,6 +516,9 @@ class _SplitBillRightPanelState extends State<SplitBillRightPanel> {
context.router.push(
PaymentRoute(
isSplit: true,
splitType: widget.state.splitType,
customerId: widget.state.customer?.id,
order: widget.state.order.copyWith(
orderItems: splitItems,
subtotal: splitTotal,
@@ -528,6 +537,9 @@ class _SplitBillRightPanelState extends State<SplitBillRightPanel> {
widget.state.totalAmount <= totalAmount) {
context.router.push(
PaymentRoute(
isSplit: true,
splitType: widget.state.splitType,
customerId: widget.state.customer?.id,
order: widget.state.order.copyWith(
subtotal: widget.state.totalAmount,
totalAmount: widget.state.totalAmount,