2025-10-31 14:33:02 +07:00

373 lines
16 KiB
Dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/void/void_form/void_form_bloc.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../common/types/void_type.dart';
import '../../../components/button/button.dart';
import '../../../components/dialog/order/order_void_confirm_dialog.dart';
import '../../../components/field/field.dart';
import '../../../components/spaces/space.dart';
import 'void_radio.dart';
class VoidRightPanel extends StatefulWidget {
final VoidFormState state;
const VoidRightPanel({super.key, required this.state});
@override
State<VoidRightPanel> createState() => _VoidRightPanelState();
}
class _VoidRightPanelState extends State<VoidRightPanel> {
final ScrollController _scrollController = ScrollController();
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1, color: AppColor.border),
),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
child: Row(
children: [
Text(
'Konfigurasi Void',
style: AppStyle.xxl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
],
),
),
Expanded(
child: Scrollbar(
controller: _scrollController,
thumbVisibility: true,
child: SingleChildScrollView(
controller: _scrollController,
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Tipe Void *',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
SpaceHeight(12),
VoidRadio(
voidType: widget.state.voidType,
value: VoidType.all,
title: 'Batalkan Seluruh Pesanan',
subtitle: "Batalkan pesanan lengkap dan semua item",
onChanged: (VoidType? value) {
context.read<VoidFormBloc>().add(
VoidFormEvent.clearSelectedItem(),
);
context.read<VoidFormBloc>().add(
VoidFormEvent.voidTypeChanged(value!),
);
},
),
SpaceHeight(12),
VoidRadio(
voidType: widget.state.voidType,
value: VoidType.item,
title: 'Batalkan Barang/Jumlah Tertentu',
subtitle:
"Mengurangi atau membatalkan jumlah item tertentu",
onChanged: (VoidType? value) {
context.read<VoidFormBloc>().add(
VoidFormEvent.voidTypeChanged(value!),
);
},
),
SpaceHeight(24),
// Selected Items Summary (only show for item void)
if (widget.state.voidType.isItem) ...[
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: widget.state.selectedItemQuantities.isEmpty
? AppColor.warning.withOpacity(0.1)
: AppColor.success.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: widget.state.selectedItemQuantities.isEmpty
? AppColor.warning.withOpacity(0.6)
: AppColor.success.withOpacity(0.6),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
widget.state.selectedItemQuantities.isEmpty
? Icons.warning
: Icons.check_circle,
color:
widget
.state
.selectedItemQuantities
.isEmpty
? AppColor.warning
: AppColor.success,
size: 20,
),
SpaceWidth(8),
Expanded(
child: Text(
widget.state.selectedItemQuantities.isEmpty
? 'Silakan pilih item dan jumlah yang akan dibatalkan'
: 'Item yang dipilih untuk dibatalkan:',
style: AppStyle.md.copyWith(
fontWeight: FontWeight.w500,
color:
widget
.state
.selectedItemQuantities
.isEmpty
? AppColor.warning
: AppColor.success,
),
),
),
],
),
if (widget
.state
.selectedItemQuantities
.isNotEmpty) ...[
SpaceHeight(12),
Container(
constraints: BoxConstraints(maxHeight: 150),
child: Scrollbar(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: widget
.state
.selectedItemQuantities
.entries
.map((entry) {
final item = widget
.state
.order
.orderItems
.firstWhere(
(item) =>
item.id == entry.key,
);
return Container(
margin: EdgeInsets.only(
bottom: 8,
),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(6),
border: Border.all(
color: AppColor.success,
),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
item.productName,
style: AppStyle.sm
.copyWith(
fontWeight:
FontWeight
.w500,
),
),
Text(
'Qty: ${entry.value}',
style: AppStyle.xs
.copyWith(
color: AppColor
.textSecondary,
),
),
],
),
),
Text(
((item.unitPrice) *
entry.value)
.currencyFormatRpV2,
style: AppStyle.xs.copyWith(
fontWeight:
FontWeight.bold,
color: AppColor.error,
),
),
],
),
);
})
.toList(),
),
),
),
),
Divider(height: 16, thickness: 1),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.error,
borderRadius: BorderRadius.circular(6),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Jumlah Total Void:',
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
widget
.state
.totalPriceVoid
.currencyFormatRpV2,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
],
],
),
),
SpaceHeight(24),
],
Text(
'Alasan Void *',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
SpaceHeight(8),
AppTextFormField(
label: 'Harap berikan alasan untuk membatalkan...',
showLabel: false,
maxLines: 4,
onChanged: (value) {
context.read<VoidFormBloc>().add(
VoidFormEvent.voidReasonChanged(value),
);
},
),
SpaceHeight(32),
],
),
),
),
),
// Action Buttons
Padding(
padding: EdgeInsets.all(20),
child: Row(
children: [
Expanded(
child: AppElevatedButton.outlined(
onPressed: () => context.router.maybePop(),
label: 'Batal',
),
),
SpaceWidth(12),
Expanded(
child: AppElevatedButton.filled(
onPressed: _canProcessVoid() ? _processVoid : null,
label: widget.state.voidType.isAll
? 'Void Pesanan'
: 'Void Produk',
),
),
],
),
),
],
),
);
}
bool _canProcessVoid() {
if (widget.state.voidReason?.isEmpty ?? true) return false;
if (widget.state.voidType.isItem &&
widget.state.selectedItemQuantities.isEmpty) {
return false;
}
return true;
}
void _processVoid() {
String confirmMessage;
if (widget.state.voidType.isAll) {
confirmMessage =
'Apakah Anda yakin ingin membatalkan seluruh pesanan #${widget.state.order.orderNumber}?\n\nIni akan membatalkan semua item dalam pesanan.';
} else {
int totalItems = widget.state.selectedItemQuantities.values.fold(
0,
(sum, qty) => sum + qty,
);
confirmMessage =
'Apakah Anda yakin ingin membatalkan $totalItems item dari pesanan #${widget.state.order.orderNumber}?\n\nJumlah Batal: ${widget.state.totalPriceVoid.currencyFormatRpV2}';
}
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return OrderVoidConfirmDialog(message: confirmMessage);
},
);
}
}