feat: update dropdown

This commit is contained in:
efrilm 2025-08-06 19:28:51 +07:00
parent 5e9d5040e7
commit c667584b11
6 changed files with 414 additions and 96 deletions

View File

@ -3255,10 +3255,10 @@ class __$$UpdateDeliveryTypeImplCopyWithImpl<$Res>
@pragma('vm:prefer-inline')
@override
$Res call({
Object? delivery = freezed,
Object? delivery = null,
}) {
return _then(_$UpdateDeliveryTypeImpl(
freezed == delivery
null == delivery
? _value.delivery
: delivery // ignore: cast_nullable_to_non_nullable
as DeliveryModel,
@ -3284,12 +3284,12 @@ class _$UpdateDeliveryTypeImpl implements _UpdateDeliveryType {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$UpdateDeliveryTypeImpl &&
const DeepCollectionEquality().equals(other.delivery, delivery));
(identical(other.delivery, delivery) ||
other.delivery == delivery));
}
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(delivery));
int get hashCode => Object.hash(runtimeType, delivery);
/// Create a copy of CheckoutEvent
/// with the given fields replaced by the non-null parameter values.
@ -4063,8 +4063,8 @@ class _$LoadedImpl implements _Loaded {
other.draftName == draftName) &&
(identical(other.orderType, orderType) ||
other.orderType == orderType) &&
const DeepCollectionEquality()
.equals(other.deliveryType, deliveryType));
(identical(other.deliveryType, deliveryType) ||
other.deliveryType == deliveryType));
}
@override
@ -4080,7 +4080,7 @@ class _$LoadedImpl implements _Loaded {
totalPrice,
draftName,
orderType,
const DeepCollectionEquality().hash(deliveryType));
deliveryType);
/// Create a copy of CheckoutState
/// with the given fields replaced by the non-null parameter values.

View File

@ -1,3 +1,6 @@
import 'dart:developer';
import 'package:dropdown_search/dropdown_search.dart';
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';
@ -31,6 +34,7 @@ class _PaymentAddOrderDialogState extends State<PaymentAddOrderDialog> {
'pending',
dateFrom: DateTime.now(),
dateTo: DateTime.now(),
limit: 20,
),
);
}
@ -97,40 +101,183 @@ class _PaymentAddOrderDialogState extends State<PaymentAddOrderDialog> {
);
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Theme.of(context).primaryColor,
width: 2,
return DropdownSearch<Order>(
items: orders,
selectedItem: selectOrder,
// Dropdown properties
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
hintText: "Pilih Meja",
hintStyle: TextStyle(
color: Colors.grey.shade600,
fontSize: 14,
),
prefixIcon: Icon(
Icons.category_outlined,
color: Colors.grey.shade500,
size: 20,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade300,
width: 1.5,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade300,
width: 1.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.blue.shade400,
width: 2,
),
),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<Order>(
isExpanded: true,
value: availableOrders.firstWhere(
(t) => t.id == selectOrder?.id,
orElse: () => availableOrders.first,
// Popup properties
popupProps: PopupProps.menu(
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Cari meja...",
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
),
onChanged: (Order? newValue) {
setState(() {
selectOrder = newValue;
});
},
items: availableOrders
.map<DropdownMenuItem<Order>>(
(Order value) => DropdownMenuItem<Order>(
value: value,
child: Text(
"${value.tableNumber ?? ""} - ${value.metadata?['customer_name'] ?? ""}",
),
menuProps: MenuProps(
backgroundColor: Colors.white,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
itemBuilder: (context, order, isSelected) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
decoration: BoxDecoration(
color: isSelected
? Colors.blue.shade50
: Colors.transparent,
border: Border(
bottom: BorderSide(
color: Colors.grey.shade100,
width: 0.5,
),
),
),
child: Row(
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: isSelected
? Colors.blue.shade600
: Colors.grey.shade400,
shape: BoxShape.circle,
),
),
)
.toList(),
),
const SizedBox(width: 12),
Expanded(
child: Text(
"${order.tableNumber ?? ""} - ${order.metadata?['customer_name']}",
style: TextStyle(
fontSize: 14,
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w500,
color: isSelected
? Colors.blue.shade700
: Colors.black87,
),
),
),
if (isSelected)
Icon(
Icons.check,
color: Colors.blue.shade600,
size: 18,
),
],
),
);
},
emptyBuilder: (context, searchEntry) {
return Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.search_off,
color: Colors.grey.shade400,
size: 48,
),
const SizedBox(height: 12),
Text(
searchEntry.isEmpty
? "Tidak ada meja tersedia"
: "Tidak ditemukan meja dengan '${searchEntry}'",
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 14,
),
textAlign: TextAlign.center,
),
],
),
);
},
),
// Item as string (for search functionality)
itemAsString: (Order order) => order.tableNumber ?? "",
// Comparison function
compareFn: (Order? item1, Order? item2) {
return item1?.id == item2?.id;
},
// On changed callback
onChanged: (Order? selectedOrder) {
if (selectedOrder != null) {
setState(() {
selectOrder = selectedOrder;
});
log("selectOrder: ${selectOrder!.tableNumber}");
}
},
// Validator (optional)
validator: (Order? value) {
if (value == null) {
return "Meja harus dipilih";
}
return null;
},
);
},
);

View File

@ -1,3 +1,6 @@
import 'dart:developer';
import 'package:dropdown_search/dropdown_search.dart';
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';
@ -103,39 +106,183 @@ class _PaymentSaveDialogState extends State<PaymentSaveDialog> {
);
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Theme.of(context).primaryColor,
width: 2,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<TableModel>(
isExpanded: true,
value: availableTables.firstWhere(
(t) => t.id == selectTable?.id,
orElse: () => availableTables.first,
return DropdownSearch<TableModel>(
items: tables,
selectedItem: selectTable,
// Dropdown properties
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
hintText: "Pilih meja",
hintStyle: TextStyle(
color: Colors.grey.shade600,
fontSize: 14,
),
prefixIcon: Icon(
Icons.category_outlined,
color: Colors.grey.shade500,
size: 20,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade300,
width: 1.5,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade300,
width: 1.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.blue.shade400,
width: 2,
),
),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
onChanged: (TableModel? newValue) {
setState(() {
selectTable = newValue;
});
},
items: availableTables
.map<DropdownMenuItem<TableModel>>(
(TableModel value) =>
DropdownMenuItem<TableModel>(
value: value,
child: Text(value.tableName ?? ""),
),
)
.toList(),
),
),
// Popup properties
popupProps: PopupProps.menu(
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Cari meja...",
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
),
),
menuProps: MenuProps(
backgroundColor: Colors.white,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
itemBuilder: (context, category, isSelected) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
decoration: BoxDecoration(
color: isSelected
? Colors.blue.shade50
: Colors.transparent,
border: Border(
bottom: BorderSide(
color: Colors.grey.shade100,
width: 0.5,
),
),
),
child: Row(
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: isSelected
? Colors.blue.shade600
: Colors.grey.shade400,
shape: BoxShape.circle,
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
category.tableName ?? "",
style: TextStyle(
fontSize: 14,
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w500,
color: isSelected
? Colors.blue.shade700
: Colors.black87,
),
),
),
if (isSelected)
Icon(
Icons.check,
color: Colors.blue.shade600,
size: 18,
),
],
),
);
},
emptyBuilder: (context, searchEntry) {
return Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.search_off,
color: Colors.grey.shade400,
size: 48,
),
const SizedBox(height: 12),
Text(
searchEntry.isEmpty
? "Tidak ada meja tersedia"
: "Tidak ditemukan meja dengan '${searchEntry}'",
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 14,
),
textAlign: TextAlign.center,
),
],
),
);
},
),
// Item as string (for search functionality)
itemAsString: (TableModel table) => table.tableName ?? "",
// Comparison function
compareFn: (TableModel? item1, TableModel? item2) {
return item1?.id == item2?.id;
},
// On changed callback
onChanged: (TableModel? selectedTable) {
if (selectedTable != null) {
setState(() {
selectTable = selectedTable;
});
log("selectTable: ${selectTable!.tableName}");
}
},
// Validator (optional)
validator: (TableModel? value) {
if (value == null) {
return "Meja harus dipilih";
}
return null;
},
);
},
);

View File

@ -56,7 +56,7 @@ class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
final result = await _orderRemoteDatasource.getOrder(
page: 1,
limit: 10,
limit: event.limit ?? 10,
status: event.status,
dateFrom: event.dateFrom,
dateTo: event.dateTo,

View File

@ -18,7 +18,8 @@ final _privateConstructorUsedError = UnsupportedError(
mixin _$OrderLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
required TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)
getByStatus,
required TResult Function(String id) getById,
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
@ -28,7 +29,8 @@ mixin _$OrderLoaderEvent {
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult? Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult? Function(String id)? getById,
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -38,7 +40,8 @@ mixin _$OrderLoaderEvent {
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult Function(String id)? getById,
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -101,7 +104,7 @@ abstract class _$$GetByStatusImplCopyWith<$Res> {
_$GetByStatusImpl value, $Res Function(_$GetByStatusImpl) then) =
__$$GetByStatusImplCopyWithImpl<$Res>;
@useResult
$Res call({String status, DateTime dateFrom, DateTime dateTo});
$Res call({String status, DateTime dateFrom, DateTime dateTo, int? limit});
}
/// @nodoc
@ -120,6 +123,7 @@ class __$$GetByStatusImplCopyWithImpl<$Res>
Object? status = null,
Object? dateFrom = null,
Object? dateTo = null,
Object? limit = freezed,
}) {
return _then(_$GetByStatusImpl(
null == status
@ -134,6 +138,10 @@ class __$$GetByStatusImplCopyWithImpl<$Res>
? _value.dateTo
: dateTo // ignore: cast_nullable_to_non_nullable
as DateTime,
limit: freezed == limit
? _value.limit
: limit // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
@ -142,7 +150,7 @@ class __$$GetByStatusImplCopyWithImpl<$Res>
class _$GetByStatusImpl implements _GetByStatus {
const _$GetByStatusImpl(this.status,
{required this.dateFrom, required this.dateTo});
{required this.dateFrom, required this.dateTo, this.limit});
@override
final String status;
@ -150,10 +158,12 @@ class _$GetByStatusImpl implements _GetByStatus {
final DateTime dateFrom;
@override
final DateTime dateTo;
@override
final int? limit;
@override
String toString() {
return 'OrderLoaderEvent.getByStatus(status: $status, dateFrom: $dateFrom, dateTo: $dateTo)';
return 'OrderLoaderEvent.getByStatus(status: $status, dateFrom: $dateFrom, dateTo: $dateTo, limit: $limit)';
}
@override
@ -164,11 +174,12 @@ class _$GetByStatusImpl implements _GetByStatus {
(identical(other.status, status) || other.status == status) &&
(identical(other.dateFrom, dateFrom) ||
other.dateFrom == dateFrom) &&
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
(identical(other.dateTo, dateTo) || other.dateTo == dateTo) &&
(identical(other.limit, limit) || other.limit == limit));
}
@override
int get hashCode => Object.hash(runtimeType, status, dateFrom, dateTo);
int get hashCode => Object.hash(runtimeType, status, dateFrom, dateTo, limit);
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@ -181,33 +192,36 @@ class _$GetByStatusImpl implements _GetByStatus {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
required TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)
getByStatus,
required TResult Function(String id) getById,
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
loadMore,
required TResult Function(String status) refresh,
}) {
return getByStatus(status, dateFrom, dateTo);
return getByStatus(status, dateFrom, dateTo, limit);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult? Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult? Function(String id)? getById,
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
loadMore,
TResult? Function(String status)? refresh,
}) {
return getByStatus?.call(status, dateFrom, dateTo);
return getByStatus?.call(status, dateFrom, dateTo, limit);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult Function(String id)? getById,
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -216,7 +230,7 @@ class _$GetByStatusImpl implements _GetByStatus {
required TResult orElse(),
}) {
if (getByStatus != null) {
return getByStatus(status, dateFrom, dateTo);
return getByStatus(status, dateFrom, dateTo, limit);
}
return orElse();
}
@ -262,11 +276,13 @@ class _$GetByStatusImpl implements _GetByStatus {
abstract class _GetByStatus implements OrderLoaderEvent {
const factory _GetByStatus(final String status,
{required final DateTime dateFrom,
required final DateTime dateTo}) = _$GetByStatusImpl;
required final DateTime dateTo,
final int? limit}) = _$GetByStatusImpl;
String get status;
DateTime get dateFrom;
DateTime get dateTo;
int? get limit;
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@ -343,7 +359,8 @@ class _$GetByIdImpl implements _GetById {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
required TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)
getByStatus,
required TResult Function(String id) getById,
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
@ -356,7 +373,8 @@ class _$GetByIdImpl implements _GetById {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult? Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult? Function(String id)? getById,
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -369,7 +387,8 @@ class _$GetByIdImpl implements _GetById {
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult Function(String id)? getById,
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -519,7 +538,8 @@ class _$LoadMoreImpl implements _LoadMore {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
required TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)
getByStatus,
required TResult Function(String id) getById,
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
@ -532,7 +552,8 @@ class _$LoadMoreImpl implements _LoadMore {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult? Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult? Function(String id)? getById,
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -545,7 +566,8 @@ class _$LoadMoreImpl implements _LoadMore {
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult Function(String id)? getById,
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -681,7 +703,8 @@ class _$RefreshImpl implements _Refresh {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
required TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)
getByStatus,
required TResult Function(String id) getById,
required TResult Function(String status, DateTime dateFrom, DateTime dateTo)
@ -694,7 +717,8 @@ class _$RefreshImpl implements _Refresh {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult? Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult? Function(String id)? getById,
TResult? Function(String status, DateTime dateFrom, DateTime dateTo)?
@ -707,7 +731,8 @@ class _$RefreshImpl implements _Refresh {
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?
TResult Function(
String status, DateTime dateFrom, DateTime dateTo, int? limit)?
getByStatus,
TResult Function(String id)? getById,
TResult Function(String status, DateTime dateFrom, DateTime dateTo)?

View File

@ -2,11 +2,10 @@ part of 'order_loader_bloc.dart';
@freezed
class OrderLoaderEvent with _$OrderLoaderEvent {
const factory OrderLoaderEvent.getByStatus(
String status, {
required DateTime dateFrom,
required DateTime dateTo,
}) = _GetByStatus;
const factory OrderLoaderEvent.getByStatus(String status,
{required DateTime dateFrom,
required DateTime dateTo,
int? limit}) = _GetByStatus;
const factory OrderLoaderEvent.getById(String id) = _GetById;
const factory OrderLoaderEvent.loadMore(
String status, {