feat: customer auto complete

This commit is contained in:
efrilm 2025-08-04 14:08:13 +07:00
parent c7f473eb5f
commit a63328d953
2 changed files with 130 additions and 21 deletions

View File

@ -4,11 +4,13 @@ import 'dart:developer';
import 'package:enaklo_pos/core/components/dashed_divider.dart';
import 'package:enaklo_pos/core/components/flushbar.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/data/models/response/customer_response_model.dart';
import 'package:enaklo_pos/presentation/home/bloc/order_form/order_form_bloc.dart';
import 'package:enaklo_pos/presentation/home/dialog/save_dialog.dart';
import 'package:enaklo_pos/presentation/home/models/order_type.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:enaklo_pos/presentation/home/widgets/confirm_payment_title.dart';
import 'package:enaklo_pos/presentation/home/widgets/customer_auto_complete_field.dart';
import 'package:enaklo_pos/presentation/success/pages/success_order_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -51,6 +53,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
int uangPas = 0;
int uangPas2 = 0;
int uangPas3 = 0;
Customer? selectedCustomer;
// int discountAmountValue = 0;
int totalPriceFinal = 0;
@ -541,27 +544,14 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Pelanggan',
style: TextStyle(
color: AppColors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(6.0),
TextFormField(
controller: customerController,
decoration: InputDecoration(
hintText: 'Nama Pelanggan',
),
textCapitalization:
TextCapitalization.words,
),
],
child: CustomerAutocomplete(
controller: customerController,
selectedCustomer: selectedCustomer,
onSelected: (customer) {
setState(() {
selectedCustomer = customer;
});
},
),
),
Container(

View File

@ -0,0 +1,119 @@
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/data/models/response/customer_response_model.dart';
import 'package:enaklo_pos/presentation/customer/bloc/customer_loader/customer_loader_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CustomerAutocomplete extends StatefulWidget {
final TextEditingController controller;
final Customer? selectedCustomer;
final ValueChanged<Customer?>? onSelected;
const CustomerAutocomplete({
super.key,
required this.controller,
this.selectedCustomer,
this.onSelected,
});
@override
State<CustomerAutocomplete> createState() => _CustomerAutocompleteState();
}
class _CustomerAutocompleteState extends State<CustomerAutocomplete> {
final FocusNode _focusNode = FocusNode();
@override
void initState() {
super.initState();
context.read<CustomerLoaderBloc>().add(CustomerLoaderEvent.getCustomer());
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Pelanggan',
style: TextStyle(
color: AppColors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(6.0),
BlocBuilder<CustomerLoaderBloc, CustomerLoaderState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () => const SizedBox.shrink(),
loading: () => const Center(child: CircularProgressIndicator()),
loaded: (customers, totalCustomer) => RawAutocomplete<Customer>(
textEditingController: widget.controller,
focusNode: _focusNode,
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Customer>.empty();
}
return customers.where((Customer customer) {
return customer.name?.toLowerCase().contains(
textEditingValue.text.toLowerCase(),
) ??
false;
});
},
displayStringForOption: (Customer option) => option.name ?? "",
onSelected: (Customer selection) {
widget.controller.text = selection.name ?? "";
if (widget.onSelected != null) {
widget.onSelected!(selection);
}
},
fieldViewBuilder:
(context, controller, focusNode, onFieldSubmitted) {
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: const InputDecoration(
hintText: 'Nama Pelanggan',
),
onChanged: (value) {
if (widget.onSelected != null) {
widget.onSelected!(null); // reset jika ketik manual
}
},
);
},
optionsViewBuilder: (context, onSelected, options) {
return Material(
elevation: 1,
borderRadius: BorderRadius.circular(8),
color: Colors.white,
child: SizedBox(
height: context.deviceHeight * 0.4,
child: ListView.separated(
padding: EdgeInsets.zero,
itemCount: options.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (BuildContext context, int index) {
final Customer option = options.elementAt(index);
return ListTile(
title: Text(option.name ?? ""),
onTap: () {
onSelected(option);
},
);
},
),
),
);
},
),
);
},
),
],
);
}
}