feat: invetory range date

This commit is contained in:
efrilm 2025-08-18 17:27:36 +07:00
parent fb2309ddb3
commit aac3eecf95
6 changed files with 406 additions and 125 deletions

View File

@ -24,6 +24,9 @@ class InventoryAnalyticLoaderBloc
Emitter<InventoryAnalyticLoaderState> emit, Emitter<InventoryAnalyticLoaderState> emit,
) { ) {
return event.map( return event.map(
rangeDateChanged: (e) async {
emit(state.copyWith(dateFrom: e.dateFrom, dateTo: e.dateTo));
},
fetched: (e) async { fetched: (e) async {
emit( emit(
state.copyWith( state.copyWith(
@ -33,8 +36,8 @@ class InventoryAnalyticLoaderBloc
); );
final result = await _repository.getInventory( final result = await _repository.getInventory(
dateFrom: DateTime.now().subtract(const Duration(days: 30)), dateFrom: state.dateFrom,
dateTo: DateTime.now(), dateTo: state.dateTo,
); );
var data = result.fold( var data = result.fold(

View File

@ -19,27 +19,34 @@ final _privateConstructorUsedError = UnsupportedError(
mixin _$InventoryAnalyticLoaderEvent { mixin _$InventoryAnalyticLoaderEvent {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function() fetched, required TResult Function() fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function()? fetched, TResult? Function()? fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function()? fetched, TResult Function()? fetched,
required TResult orElse(), required TResult orElse(),
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({ TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@ -74,6 +81,165 @@ class _$InventoryAnalyticLoaderEventCopyWithImpl<
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
} }
/// @nodoc
abstract class _$$RangeDateChangedImplCopyWith<$Res> {
factory _$$RangeDateChangedImplCopyWith(
_$RangeDateChangedImpl value,
$Res Function(_$RangeDateChangedImpl) then,
) = __$$RangeDateChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({DateTime dateFrom, DateTime dateTo});
}
/// @nodoc
class __$$RangeDateChangedImplCopyWithImpl<$Res>
extends
_$InventoryAnalyticLoaderEventCopyWithImpl<$Res, _$RangeDateChangedImpl>
implements _$$RangeDateChangedImplCopyWith<$Res> {
__$$RangeDateChangedImplCopyWithImpl(
_$RangeDateChangedImpl _value,
$Res Function(_$RangeDateChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of InventoryAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? dateFrom = null, Object? dateTo = null}) {
return _then(
_$RangeDateChangedImpl(
null == dateFrom
? _value.dateFrom
: dateFrom // ignore: cast_nullable_to_non_nullable
as DateTime,
null == dateTo
? _value.dateTo
: dateTo // ignore: cast_nullable_to_non_nullable
as DateTime,
),
);
}
}
/// @nodoc
class _$RangeDateChangedImpl implements _RangeDateChanged {
const _$RangeDateChangedImpl(this.dateFrom, this.dateTo);
@override
final DateTime dateFrom;
@override
final DateTime dateTo;
@override
String toString() {
return 'InventoryAnalyticLoaderEvent.rangeDateChanged(dateFrom: $dateFrom, dateTo: $dateTo)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$RangeDateChangedImpl &&
(identical(other.dateFrom, dateFrom) ||
other.dateFrom == dateFrom) &&
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
}
@override
int get hashCode => Object.hash(runtimeType, dateFrom, dateTo);
/// Create a copy of InventoryAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$RangeDateChangedImplCopyWith<_$RangeDateChangedImpl> get copyWith =>
__$$RangeDateChangedImplCopyWithImpl<_$RangeDateChangedImpl>(
this,
_$identity,
);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function() fetched,
}) {
return rangeDateChanged(dateFrom, dateTo);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function()? fetched,
}) {
return rangeDateChanged?.call(dateFrom, dateTo);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function()? fetched,
required TResult orElse(),
}) {
if (rangeDateChanged != null) {
return rangeDateChanged(dateFrom, dateTo);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_Fetched value) fetched,
}) {
return rangeDateChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return rangeDateChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (rangeDateChanged != null) {
return rangeDateChanged(this);
}
return orElse();
}
}
abstract class _RangeDateChanged implements InventoryAnalyticLoaderEvent {
const factory _RangeDateChanged(
final DateTime dateFrom,
final DateTime dateTo,
) = _$RangeDateChangedImpl;
DateTime get dateFrom;
DateTime get dateTo;
/// Create a copy of InventoryAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$RangeDateChangedImplCopyWith<_$RangeDateChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc /// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> { abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith( factory _$$FetchedImplCopyWith(
@ -116,19 +282,27 @@ class _$FetchedImpl implements _Fetched {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({required TResult Function() fetched}) { TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function() fetched,
}) {
return fetched(); return fetched();
} }
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched}) { TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function()? fetched,
}) {
return fetched?.call(); return fetched?.call();
} }
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function()? fetched, TResult Function()? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -141,6 +315,7 @@ class _$FetchedImpl implements _Fetched {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) { }) {
return fetched(this); return fetched(this);
@ -149,6 +324,7 @@ class _$FetchedImpl implements _Fetched {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({ TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) { }) {
return fetched?.call(this); return fetched?.call(this);
@ -157,6 +333,7 @@ class _$FetchedImpl implements _Fetched {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -177,6 +354,8 @@ mixin _$InventoryAnalyticLoaderState {
Option<AnalyticFailure> get failureOptionInventoryAnalytic => Option<AnalyticFailure> get failureOptionInventoryAnalytic =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError; bool get isFetching => throw _privateConstructorUsedError;
DateTime get dateFrom => throw _privateConstructorUsedError;
DateTime get dateTo => throw _privateConstructorUsedError;
/// Create a copy of InventoryAnalyticLoaderState /// Create a copy of InventoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@ -200,6 +379,8 @@ abstract class $InventoryAnalyticLoaderStateCopyWith<$Res> {
InventoryAnalytic inventoryAnalytic, InventoryAnalytic inventoryAnalytic,
Option<AnalyticFailure> failureOptionInventoryAnalytic, Option<AnalyticFailure> failureOptionInventoryAnalytic,
bool isFetching, bool isFetching,
DateTime dateFrom,
DateTime dateTo,
}); });
$InventoryAnalyticCopyWith<$Res> get inventoryAnalytic; $InventoryAnalyticCopyWith<$Res> get inventoryAnalytic;
@ -226,6 +407,8 @@ class _$InventoryAnalyticLoaderStateCopyWithImpl<
Object? inventoryAnalytic = null, Object? inventoryAnalytic = null,
Object? failureOptionInventoryAnalytic = null, Object? failureOptionInventoryAnalytic = null,
Object? isFetching = null, Object? isFetching = null,
Object? dateFrom = null,
Object? dateTo = null,
}) { }) {
return _then( return _then(
_value.copyWith( _value.copyWith(
@ -242,6 +425,14 @@ class _$InventoryAnalyticLoaderStateCopyWithImpl<
? _value.isFetching ? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable : isFetching // ignore: cast_nullable_to_non_nullable
as bool, as bool,
dateFrom: null == dateFrom
? _value.dateFrom
: dateFrom // ignore: cast_nullable_to_non_nullable
as DateTime,
dateTo: null == dateTo
? _value.dateTo
: dateTo // ignore: cast_nullable_to_non_nullable
as DateTime,
) )
as $Val, as $Val,
); );
@ -271,6 +462,8 @@ abstract class _$$InventoryAnalyticLoaderStateImplCopyWith<$Res>
InventoryAnalytic inventoryAnalytic, InventoryAnalytic inventoryAnalytic,
Option<AnalyticFailure> failureOptionInventoryAnalytic, Option<AnalyticFailure> failureOptionInventoryAnalytic,
bool isFetching, bool isFetching,
DateTime dateFrom,
DateTime dateTo,
}); });
@override @override
@ -298,6 +491,8 @@ class __$$InventoryAnalyticLoaderStateImplCopyWithImpl<$Res>
Object? inventoryAnalytic = null, Object? inventoryAnalytic = null,
Object? failureOptionInventoryAnalytic = null, Object? failureOptionInventoryAnalytic = null,
Object? isFetching = null, Object? isFetching = null,
Object? dateFrom = null,
Object? dateTo = null,
}) { }) {
return _then( return _then(
_$InventoryAnalyticLoaderStateImpl( _$InventoryAnalyticLoaderStateImpl(
@ -313,6 +508,14 @@ class __$$InventoryAnalyticLoaderStateImplCopyWithImpl<$Res>
? _value.isFetching ? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable : isFetching // ignore: cast_nullable_to_non_nullable
as bool, as bool,
dateFrom: null == dateFrom
? _value.dateFrom
: dateFrom // ignore: cast_nullable_to_non_nullable
as DateTime,
dateTo: null == dateTo
? _value.dateTo
: dateTo // ignore: cast_nullable_to_non_nullable
as DateTime,
), ),
); );
} }
@ -326,6 +529,8 @@ class _$InventoryAnalyticLoaderStateImpl
required this.inventoryAnalytic, required this.inventoryAnalytic,
required this.failureOptionInventoryAnalytic, required this.failureOptionInventoryAnalytic,
this.isFetching = false, this.isFetching = false,
required this.dateFrom,
required this.dateTo,
}); });
@override @override
@ -335,10 +540,14 @@ class _$InventoryAnalyticLoaderStateImpl
@override @override
@JsonKey() @JsonKey()
final bool isFetching; final bool isFetching;
@override
final DateTime dateFrom;
@override
final DateTime dateTo;
@override @override
String toString() { String toString() {
return 'InventoryAnalyticLoaderState(inventoryAnalytic: $inventoryAnalytic, failureOptionInventoryAnalytic: $failureOptionInventoryAnalytic, isFetching: $isFetching)'; return 'InventoryAnalyticLoaderState(inventoryAnalytic: $inventoryAnalytic, failureOptionInventoryAnalytic: $failureOptionInventoryAnalytic, isFetching: $isFetching, dateFrom: $dateFrom, dateTo: $dateTo)';
} }
@override @override
@ -355,7 +564,10 @@ class _$InventoryAnalyticLoaderStateImpl
other.failureOptionInventoryAnalytic == other.failureOptionInventoryAnalytic ==
failureOptionInventoryAnalytic) && failureOptionInventoryAnalytic) &&
(identical(other.isFetching, isFetching) || (identical(other.isFetching, isFetching) ||
other.isFetching == isFetching)); other.isFetching == isFetching) &&
(identical(other.dateFrom, dateFrom) ||
other.dateFrom == dateFrom) &&
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
} }
@override @override
@ -364,6 +576,8 @@ class _$InventoryAnalyticLoaderStateImpl
inventoryAnalytic, inventoryAnalytic,
failureOptionInventoryAnalytic, failureOptionInventoryAnalytic,
isFetching, isFetching,
dateFrom,
dateTo,
); );
/// Create a copy of InventoryAnalyticLoaderState /// Create a copy of InventoryAnalyticLoaderState
@ -386,6 +600,8 @@ abstract class _InventoryAnalyticLoaderState
required final InventoryAnalytic inventoryAnalytic, required final InventoryAnalytic inventoryAnalytic,
required final Option<AnalyticFailure> failureOptionInventoryAnalytic, required final Option<AnalyticFailure> failureOptionInventoryAnalytic,
final bool isFetching, final bool isFetching,
required final DateTime dateFrom,
required final DateTime dateTo,
}) = _$InventoryAnalyticLoaderStateImpl; }) = _$InventoryAnalyticLoaderStateImpl;
@override @override
@ -394,6 +610,10 @@ abstract class _InventoryAnalyticLoaderState
Option<AnalyticFailure> get failureOptionInventoryAnalytic; Option<AnalyticFailure> get failureOptionInventoryAnalytic;
@override @override
bool get isFetching; bool get isFetching;
@override
DateTime get dateFrom;
@override
DateTime get dateTo;
/// Create a copy of InventoryAnalyticLoaderState /// Create a copy of InventoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.

View File

@ -2,5 +2,9 @@ part of 'inventory_analytic_loader_bloc.dart';
@freezed @freezed
class InventoryAnalyticLoaderEvent with _$InventoryAnalyticLoaderEvent { class InventoryAnalyticLoaderEvent with _$InventoryAnalyticLoaderEvent {
const factory InventoryAnalyticLoaderEvent.rangeDateChanged(
DateTime dateFrom,
DateTime dateTo,
) = _RangeDateChanged;
const factory InventoryAnalyticLoaderEvent.fetched() = _Fetched; const factory InventoryAnalyticLoaderEvent.fetched() = _Fetched;
} }

View File

@ -6,11 +6,15 @@ class InventoryAnalyticLoaderState with _$InventoryAnalyticLoaderState {
required InventoryAnalytic inventoryAnalytic, required InventoryAnalytic inventoryAnalytic,
required Option<AnalyticFailure> failureOptionInventoryAnalytic, required Option<AnalyticFailure> failureOptionInventoryAnalytic,
@Default(false) bool isFetching, @Default(false) bool isFetching,
required DateTime dateFrom,
required DateTime dateTo,
}) = _InventoryAnalyticLoaderState; }) = _InventoryAnalyticLoaderState;
factory InventoryAnalyticLoaderState.initial() => factory InventoryAnalyticLoaderState.initial() =>
InventoryAnalyticLoaderState( InventoryAnalyticLoaderState(
inventoryAnalytic: InventoryAnalytic.empty(), inventoryAnalytic: InventoryAnalytic.empty(),
failureOptionInventoryAnalytic: none(), failureOptionInventoryAnalytic: none(),
dateFrom: DateTime.now().subtract(const Duration(days: 30)),
dateTo: DateTime.now(),
); );
} }

View File

@ -107,7 +107,19 @@ class _InventoryPageState extends State<InventoryPage>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return BlocListener<
InventoryAnalyticLoaderBloc,
InventoryAnalyticLoaderState
>(
listenWhen: (previous, current) =>
previous.dateFrom != current.dateFrom ||
previous.dateTo != current.dateTo,
listener: (context, state) {
context.read<InventoryAnalyticLoaderBloc>().add(
InventoryAnalyticLoaderEvent.fetched(),
);
},
child: Scaffold(
backgroundColor: AppColor.background, backgroundColor: AppColor.background,
body: body:
BlocBuilder< BlocBuilder<
@ -126,6 +138,16 @@ class _InventoryPageState extends State<InventoryPage>
SliverPersistentHeader( SliverPersistentHeader(
pinned: true, pinned: true,
delegate: InventorySliverTabBarDelegate( delegate: InventorySliverTabBarDelegate(
startDate: state.dateFrom,
endDate: state.dateTo,
onDateRangeChanged: (startDate, endDate) {
context.read<InventoryAnalyticLoaderBloc>().add(
InventoryAnalyticLoaderEvent.rangeDateChanged(
startDate!,
endDate!,
),
);
},
tabBar: TabBar( tabBar: TabBar(
controller: _tabController, controller: _tabController,
indicator: BoxDecoration( indicator: BoxDecoration(
@ -221,6 +243,7 @@ class _InventoryPageState extends State<InventoryPage>
); );
}, },
), ),
),
); );
} }

View File

@ -1,17 +1,26 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart'; import '../../../../common/theme/theme.dart';
import '../../../components/field/date_range_picker_field.dart';
class InventorySliverTabBarDelegate extends SliverPersistentHeaderDelegate { class InventorySliverTabBarDelegate extends SliverPersistentHeaderDelegate {
final TabBar tabBar; final TabBar tabBar;
final DateTime? startDate;
final DateTime? endDate;
final Function(DateTime?, DateTime?)? onDateRangeChanged;
InventorySliverTabBarDelegate({required this.tabBar}); InventorySliverTabBarDelegate({
required this.tabBar,
this.startDate,
this.endDate,
this.onDateRangeChanged,
});
@override @override
double get minExtent => 60; double get minExtent => 120; // Increased height to accommodate date picker
@override @override
double get maxExtent => 60; double get maxExtent => 120;
@override @override
Widget build( Widget build(
@ -31,7 +40,21 @@ class InventorySliverTabBarDelegate extends SliverPersistentHeaderDelegate {
], ],
), ),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
child: Container( child: Column(
children: [
// Date Range Picker Section
if (onDateRangeChanged != null)
Expanded(
child: DateRangePickerField(
maxDate: DateTime.now(),
startDate: startDate,
endDate: endDate,
onChanged: onDateRangeChanged!,
),
),
const SizedBox(height: 8),
// Tab Bar Section
Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColor.background, color: AppColor.background,
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
@ -42,11 +65,15 @@ class InventorySliverTabBarDelegate extends SliverPersistentHeaderDelegate {
), ),
child: tabBar, child: tabBar,
), ),
],
),
); );
} }
@override @override
bool shouldRebuild(InventorySliverTabBarDelegate oldDelegate) { bool shouldRebuild(InventorySliverTabBarDelegate oldDelegate) {
return false; return oldDelegate.startDate != startDate ||
oldDelegate.endDate != endDate ||
oldDelegate.tabBar != tabBar;
} }
} }