From ab2a59930c2e49b681cf4824688e04faf91158ce Mon Sep 17 00:00:00 2001 From: efrilm Date: Thu, 7 Aug 2025 12:34:57 +0700 Subject: [PATCH] feat: order search --- .../datasources/order_remote_datasource.dart | 22 ++- .../blocs/order_loader/order_loader_bloc.dart | 2 + .../order_loader_bloc.freezed.dart | 169 +++++++++++------- .../order_loader/order_loader_event.dart | 12 +- lib/presentation/sales/pages/sales_page.dart | 40 +++-- 5 files changed, 152 insertions(+), 93 deletions(-) diff --git a/lib/data/datasources/order_remote_datasource.dart b/lib/data/datasources/order_remote_datasource.dart index 0e40289..4e129bd 100644 --- a/lib/data/datasources/order_remote_datasource.dart +++ b/lib/data/datasources/order_remote_datasource.dart @@ -272,18 +272,26 @@ class OrderRemoteDatasource { String status = 'completed', required DateTime dateFrom, required DateTime dateTo, + String? search, }) async { try { final authData = await AuthLocalDataSource().getAuthData(); + + Map params = { + 'page': page, + 'limit': limit, + 'status': status, + 'date_from': DateFormat('dd-MM-yyyy').format(dateFrom), + 'date_to': DateFormat('dd-MM-yyyy').format(dateTo), + }; + + if (search != null && search.isNotEmpty) { + params['search'] = search; + } + final response = await dio.get( '${Variables.baseUrl}/api/v1/orders', - queryParameters: { - 'page': page, - 'limit': limit, - 'status': status, - 'date_from': DateFormat('dd-MM-yyyy').format(dateFrom), - 'date_to': DateFormat('dd-MM-yyyy').format(dateTo), - }, + queryParameters: params, options: Options( headers: { 'Authorization': 'Bearer ${authData.token}', diff --git a/lib/presentation/sales/blocs/order_loader/order_loader_bloc.dart b/lib/presentation/sales/blocs/order_loader/order_loader_bloc.dart index 35e4b64..681ed2a 100644 --- a/lib/presentation/sales/blocs/order_loader/order_loader_bloc.dart +++ b/lib/presentation/sales/blocs/order_loader/order_loader_bloc.dart @@ -60,6 +60,7 @@ class OrderLoaderBloc extends Bloc { status: event.status, dateFrom: event.dateFrom, dateTo: event.dateTo, + search: event.search, ); await result.fold( @@ -108,6 +109,7 @@ class OrderLoaderBloc extends Bloc { status: event.status, dateFrom: event.dateFrom, dateTo: event.dateTo, + search: event.search, ); await result.fold( diff --git a/lib/presentation/sales/blocs/order_loader/order_loader_bloc.freezed.dart b/lib/presentation/sales/blocs/order_loader/order_loader_bloc.freezed.dart index b2960fe..96b233d 100644 --- a/lib/presentation/sales/blocs/order_loader/order_loader_bloc.freezed.dart +++ b/lib/presentation/sales/blocs/order_loader/order_loader_bloc.freezed.dart @@ -18,33 +18,36 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$OrderLoaderEvent { @optionalTypeArgs TResult when({ - required TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit) + required TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search) getByStatus, required TResult Function(String id) getById, - required TResult Function(String status, DateTime dateFrom, DateTime dateTo) + required TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search) loadMore, required TResult Function(String status) refresh, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ - TResult? Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult? Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult? Function(String id)? getById, - TResult? Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult? Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult? Function(String status)? refresh, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ - TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult Function(String id)? getById, - TResult Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult Function(String status)? refresh, required TResult orElse(), @@ -104,7 +107,12 @@ abstract class _$$GetByStatusImplCopyWith<$Res> { _$GetByStatusImpl value, $Res Function(_$GetByStatusImpl) then) = __$$GetByStatusImplCopyWithImpl<$Res>; @useResult - $Res call({String status, DateTime dateFrom, DateTime dateTo, int? limit}); + $Res call( + {String status, + DateTime dateFrom, + DateTime dateTo, + int? limit, + String? search}); } /// @nodoc @@ -124,6 +132,7 @@ class __$$GetByStatusImplCopyWithImpl<$Res> Object? dateFrom = null, Object? dateTo = null, Object? limit = freezed, + Object? search = freezed, }) { return _then(_$GetByStatusImpl( null == status @@ -142,6 +151,10 @@ class __$$GetByStatusImplCopyWithImpl<$Res> ? _value.limit : limit // ignore: cast_nullable_to_non_nullable as int?, + search: freezed == search + ? _value.search + : search // ignore: cast_nullable_to_non_nullable + as String?, )); } } @@ -150,7 +163,7 @@ class __$$GetByStatusImplCopyWithImpl<$Res> class _$GetByStatusImpl implements _GetByStatus { const _$GetByStatusImpl(this.status, - {required this.dateFrom, required this.dateTo, this.limit}); + {required this.dateFrom, required this.dateTo, this.limit, this.search}); @override final String status; @@ -160,10 +173,12 @@ class _$GetByStatusImpl implements _GetByStatus { final DateTime dateTo; @override final int? limit; + @override + final String? search; @override String toString() { - return 'OrderLoaderEvent.getByStatus(status: $status, dateFrom: $dateFrom, dateTo: $dateTo, limit: $limit)'; + return 'OrderLoaderEvent.getByStatus(status: $status, dateFrom: $dateFrom, dateTo: $dateTo, limit: $limit, search: $search)'; } @override @@ -175,11 +190,13 @@ class _$GetByStatusImpl implements _GetByStatus { (identical(other.dateFrom, dateFrom) || other.dateFrom == dateFrom) && (identical(other.dateTo, dateTo) || other.dateTo == dateTo) && - (identical(other.limit, limit) || other.limit == limit)); + (identical(other.limit, limit) || other.limit == limit) && + (identical(other.search, search) || other.search == search)); } @override - int get hashCode => Object.hash(runtimeType, status, dateFrom, dateTo, limit); + int get hashCode => + Object.hash(runtimeType, status, dateFrom, dateTo, limit, search); /// Create a copy of OrderLoaderEvent /// with the given fields replaced by the non-null parameter values. @@ -192,45 +209,48 @@ class _$GetByStatusImpl implements _GetByStatus { @override @optionalTypeArgs TResult when({ - required TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit) + required TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search) getByStatus, required TResult Function(String id) getById, - required TResult Function(String status, DateTime dateFrom, DateTime dateTo) + required TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search) loadMore, required TResult Function(String status) refresh, }) { - return getByStatus(status, dateFrom, dateTo, limit); + return getByStatus(status, dateFrom, dateTo, limit, search); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult? Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult? Function(String id)? getById, - TResult? Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult? Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult? Function(String status)? refresh, }) { - return getByStatus?.call(status, dateFrom, dateTo, limit); + return getByStatus?.call(status, dateFrom, dateTo, limit, search); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult Function(String id)? getById, - TResult Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult Function(String status)? refresh, required TResult orElse(), }) { if (getByStatus != null) { - return getByStatus(status, dateFrom, dateTo, limit); + return getByStatus(status, dateFrom, dateTo, limit, search); } return orElse(); } @@ -277,12 +297,14 @@ abstract class _GetByStatus implements OrderLoaderEvent { const factory _GetByStatus(final String status, {required final DateTime dateFrom, required final DateTime dateTo, - final int? limit}) = _$GetByStatusImpl; + final int? limit, + final String? search}) = _$GetByStatusImpl; String get status; DateTime get dateFrom; DateTime get dateTo; int? get limit; + String? get search; /// Create a copy of OrderLoaderEvent /// with the given fields replaced by the non-null parameter values. @@ -359,11 +381,12 @@ class _$GetByIdImpl implements _GetById { @override @optionalTypeArgs TResult when({ - required TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit) + required TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search) getByStatus, required TResult Function(String id) getById, - required TResult Function(String status, DateTime dateFrom, DateTime dateTo) + required TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search) loadMore, required TResult Function(String status) refresh, }) { @@ -373,11 +396,12 @@ class _$GetByIdImpl implements _GetById { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult? Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult? Function(String id)? getById, - TResult? Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult? Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult? Function(String status)? refresh, }) { @@ -387,11 +411,12 @@ class _$GetByIdImpl implements _GetById { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult Function(String id)? getById, - TResult Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult Function(String status)? refresh, required TResult orElse(), @@ -458,7 +483,8 @@ abstract class _$$LoadMoreImplCopyWith<$Res> { _$LoadMoreImpl value, $Res Function(_$LoadMoreImpl) then) = __$$LoadMoreImplCopyWithImpl<$Res>; @useResult - $Res call({String status, DateTime dateFrom, DateTime dateTo}); + $Res call( + {String status, DateTime dateFrom, DateTime dateTo, String? search}); } /// @nodoc @@ -477,6 +503,7 @@ class __$$LoadMoreImplCopyWithImpl<$Res> Object? status = null, Object? dateFrom = null, Object? dateTo = null, + Object? search = freezed, }) { return _then(_$LoadMoreImpl( null == status @@ -491,6 +518,10 @@ class __$$LoadMoreImplCopyWithImpl<$Res> ? _value.dateTo : dateTo // ignore: cast_nullable_to_non_nullable as DateTime, + search: freezed == search + ? _value.search + : search // ignore: cast_nullable_to_non_nullable + as String?, )); } } @@ -499,7 +530,7 @@ class __$$LoadMoreImplCopyWithImpl<$Res> class _$LoadMoreImpl implements _LoadMore { const _$LoadMoreImpl(this.status, - {required this.dateFrom, required this.dateTo}); + {required this.dateFrom, required this.dateTo, this.search}); @override final String status; @@ -507,10 +538,12 @@ class _$LoadMoreImpl implements _LoadMore { final DateTime dateFrom; @override final DateTime dateTo; + @override + final String? search; @override String toString() { - return 'OrderLoaderEvent.loadMore(status: $status, dateFrom: $dateFrom, dateTo: $dateTo)'; + return 'OrderLoaderEvent.loadMore(status: $status, dateFrom: $dateFrom, dateTo: $dateTo, search: $search)'; } @override @@ -521,11 +554,13 @@ class _$LoadMoreImpl implements _LoadMore { (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.search, search) || other.search == search)); } @override - int get hashCode => Object.hash(runtimeType, status, dateFrom, dateTo); + int get hashCode => + Object.hash(runtimeType, status, dateFrom, dateTo, search); /// Create a copy of OrderLoaderEvent /// with the given fields replaced by the non-null parameter values. @@ -538,45 +573,48 @@ class _$LoadMoreImpl implements _LoadMore { @override @optionalTypeArgs TResult when({ - required TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit) + required TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search) getByStatus, required TResult Function(String id) getById, - required TResult Function(String status, DateTime dateFrom, DateTime dateTo) + required TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search) loadMore, required TResult Function(String status) refresh, }) { - return loadMore(status, dateFrom, dateTo); + return loadMore(status, dateFrom, dateTo, search); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult? Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult? Function(String id)? getById, - TResult? Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult? Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult? Function(String status)? refresh, }) { - return loadMore?.call(status, dateFrom, dateTo); + return loadMore?.call(status, dateFrom, dateTo, search); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult Function(String id)? getById, - TResult Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult Function(String status)? refresh, required TResult orElse(), }) { if (loadMore != null) { - return loadMore(status, dateFrom, dateTo); + return loadMore(status, dateFrom, dateTo, search); } return orElse(); } @@ -622,11 +660,13 @@ class _$LoadMoreImpl implements _LoadMore { abstract class _LoadMore implements OrderLoaderEvent { const factory _LoadMore(final String status, {required final DateTime dateFrom, - required final DateTime dateTo}) = _$LoadMoreImpl; + required final DateTime dateTo, + final String? search}) = _$LoadMoreImpl; String get status; DateTime get dateFrom; DateTime get dateTo; + String? get search; /// Create a copy of OrderLoaderEvent /// with the given fields replaced by the non-null parameter values. @@ -703,11 +743,12 @@ class _$RefreshImpl implements _Refresh { @override @optionalTypeArgs TResult when({ - required TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit) + required TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search) getByStatus, required TResult Function(String id) getById, - required TResult Function(String status, DateTime dateFrom, DateTime dateTo) + required TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search) loadMore, required TResult Function(String status) refresh, }) { @@ -717,11 +758,12 @@ class _$RefreshImpl implements _Refresh { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult? Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult? Function(String id)? getById, - TResult? Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult? Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult? Function(String status)? refresh, }) { @@ -731,11 +773,12 @@ class _$RefreshImpl implements _Refresh { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function( - String status, DateTime dateFrom, DateTime dateTo, int? limit)? + TResult Function(String status, DateTime dateFrom, DateTime dateTo, + int? limit, String? search)? getByStatus, TResult Function(String id)? getById, - TResult Function(String status, DateTime dateFrom, DateTime dateTo)? + TResult Function( + String status, DateTime dateFrom, DateTime dateTo, String? search)? loadMore, TResult Function(String status)? refresh, required TResult orElse(), diff --git a/lib/presentation/sales/blocs/order_loader/order_loader_event.dart b/lib/presentation/sales/blocs/order_loader/order_loader_event.dart index b3d4354..3d9e886 100644 --- a/lib/presentation/sales/blocs/order_loader/order_loader_event.dart +++ b/lib/presentation/sales/blocs/order_loader/order_loader_event.dart @@ -2,15 +2,19 @@ part of 'order_loader_bloc.dart'; @freezed class OrderLoaderEvent with _$OrderLoaderEvent { - const factory OrderLoaderEvent.getByStatus(String status, - {required DateTime dateFrom, - required DateTime dateTo, - int? limit}) = _GetByStatus; + const factory OrderLoaderEvent.getByStatus( + String status, { + required DateTime dateFrom, + required DateTime dateTo, + int? limit, + String? search, + }) = _GetByStatus; const factory OrderLoaderEvent.getById(String id) = _GetById; const factory OrderLoaderEvent.loadMore( String status, { required DateTime dateFrom, required DateTime dateTo, + String? search, }) = _LoadMore; const factory OrderLoaderEvent.refresh(String status) = _Refresh; } diff --git a/lib/presentation/sales/pages/sales_page.dart b/lib/presentation/sales/pages/sales_page.dart index 6c88a23..b320fef 100644 --- a/lib/presentation/sales/pages/sales_page.dart +++ b/lib/presentation/sales/pages/sales_page.dart @@ -45,18 +45,6 @@ class _SalesPageState extends State { super.initState(); } - List _filterOrders(List orders) { - if (searchQuery.isEmpty) { - return orders; - } - - return orders.where((order) { - final customerName = order.orderNumber?.toLowerCase() ?? ""; - final queryLower = searchQuery.toLowerCase(); - return customerName.contains(queryLower); - }).toList(); - } - @override Widget build(BuildContext context) { return SafeArea( @@ -71,8 +59,13 @@ class _SalesPageState extends State { if (notification is ScrollEndNotification && scrollController.position.extentAfter == 0) { context.read().add( - OrderLoaderEvent.loadMore(widget.status, - dateFrom: startDate, dateTo: endDate)); + OrderLoaderEvent.loadMore( + widget.status, + dateFrom: startDate, + dateTo: endDate, + search: searchQuery, + ), + ); return true; } @@ -92,6 +85,16 @@ class _SalesPageState extends State { setState(() { searchQuery = value; }); + Future.delayed(const Duration(milliseconds: 800), () { + context.read().add( + OrderLoaderEvent.getByStatus( + widget.status, + dateFrom: startDate, + dateTo: endDate, + search: searchQuery, + ), + ); + }); }, onDateRangeChanged: (start, end) { setState(() { @@ -125,8 +128,7 @@ class _SalesPageState extends State { ), loaded: (orders, totalOrder, hasReachedMax, currentPage, isLoadingMore) { - final filtered = _filterOrders(orders); - if (filtered.isEmpty) { + if (orders.isEmpty) { return Center( child: Text( "Belum ada transaksi saat ini. ", @@ -138,17 +140,17 @@ class _SalesPageState extends State { ); } else { return ListView.builder( - itemCount: filtered.length, + itemCount: orders.length, controller: scrollController, itemBuilder: (context, index) { return GestureDetector( onTap: () { setState(() { - orderDetail = filtered[index]; + orderDetail = orders[index]; }); context.read().add( OrderFormEvent.started( - filtered[index])); + orders[index])); }, child: SalesCard( order: orders[index],