From a61b19e45c004e76d5d66957805f5f64a79058cd Mon Sep 17 00:00:00 2001 From: efrilm Date: Mon, 18 Aug 2025 17:06:41 +0700 Subject: [PATCH] feat: product analytic range date --- .../product_analytic_loader_bloc.dart | 7 +- .../product_analytic_loader_bloc.freezed.dart | 228 +++++++++++- .../product_analytic_loader_event.dart | 4 + .../product_analytic_loader_state.dart | 4 + lib/domain/analytic/analytic.freezed.dart | 16 +- .../entities/product_analytic_entity.dart | 4 +- .../analytic/analytic_dtos.freezed.dart | 350 +++++++++--------- .../analytic/analytic_dtos.g.dart | 28 +- .../analytic/dto/product_analytic_dto.dart | 52 +-- .../product_analytic_page.dart | 168 +++++---- lib/presentation/router/app_router.gr.dart | 2 +- 11 files changed, 554 insertions(+), 309 deletions(-) diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart index 877407c..f793510 100644 --- a/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart @@ -24,6 +24,9 @@ class ProductAnalyticLoaderBloc Emitter emit, ) { return event.map( + rangeDateChanged: (e) async { + emit(state.copyWith(dateFrom: e.dateFrom, dateTo: e.dateTo)); + }, fetched: (e) async { emit( state.copyWith( @@ -33,8 +36,8 @@ class ProductAnalyticLoaderBloc ); final result = await _repository.getProduct( - dateFrom: DateTime.now().subtract(const Duration(days: 30)), - dateTo: DateTime.now(), + dateFrom: state.dateFrom, + dateTo: state.dateTo, ); var data = result.fold( diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart index 9a7fc21..05fec87 100644 --- a/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart @@ -19,27 +19,34 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$ProductAnalyticLoaderEvent { @optionalTypeArgs TResult when({ + required TResult Function(DateTime dateFrom, DateTime dateTo) + rangeDateChanged, required TResult Function() fetched, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ + TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult? Function()? fetched, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ + TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function()? fetched, required TResult orElse(), }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ + required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_Fetched value) fetched, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ + TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_Fetched value)? fetched, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ + TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_Fetched value)? fetched, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -74,6 +81,165 @@ class _$ProductAnalyticLoaderEventCopyWithImpl< /// 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 + _$ProductAnalyticLoaderEventCopyWithImpl<$Res, _$RangeDateChangedImpl> + implements _$$RangeDateChangedImplCopyWith<$Res> { + __$$RangeDateChangedImplCopyWithImpl( + _$RangeDateChangedImpl _value, + $Res Function(_$RangeDateChangedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalyticLoaderEvent + /// 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 'ProductAnalyticLoaderEvent.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 ProductAnalyticLoaderEvent + /// 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({ + required TResult Function(DateTime dateFrom, DateTime dateTo) + rangeDateChanged, + required TResult Function() fetched, + }) { + return rangeDateChanged(dateFrom, dateTo); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, + TResult? Function()? fetched, + }) { + return rangeDateChanged?.call(dateFrom, dateTo); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + 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({ + required TResult Function(_RangeDateChanged value) rangeDateChanged, + required TResult Function(_Fetched value) fetched, + }) { + return rangeDateChanged(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_RangeDateChanged value)? rangeDateChanged, + TResult? Function(_Fetched value)? fetched, + }) { + return rangeDateChanged?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + 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 ProductAnalyticLoaderEvent { + const factory _RangeDateChanged( + final DateTime dateFrom, + final DateTime dateTo, + ) = _$RangeDateChangedImpl; + + DateTime get dateFrom; + DateTime get dateTo; + + /// Create a copy of ProductAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$RangeDateChangedImplCopyWith<_$RangeDateChangedImpl> get copyWith => + throw _privateConstructorUsedError; +} + /// @nodoc abstract class _$$FetchedImplCopyWith<$Res> { factory _$$FetchedImplCopyWith( @@ -116,19 +282,27 @@ class _$FetchedImpl implements _Fetched { @override @optionalTypeArgs - TResult when({required TResult Function() fetched}) { + TResult when({ + required TResult Function(DateTime dateFrom, DateTime dateTo) + rangeDateChanged, + required TResult Function() fetched, + }) { return fetched(); } @override @optionalTypeArgs - TResult? whenOrNull({TResult? Function()? fetched}) { + TResult? whenOrNull({ + TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, + TResult? Function()? fetched, + }) { return fetched?.call(); } @override @optionalTypeArgs TResult maybeWhen({ + TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function()? fetched, required TResult orElse(), }) { @@ -141,6 +315,7 @@ class _$FetchedImpl implements _Fetched { @override @optionalTypeArgs TResult map({ + required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_Fetched value) fetched, }) { return fetched(this); @@ -149,6 +324,7 @@ class _$FetchedImpl implements _Fetched { @override @optionalTypeArgs TResult? mapOrNull({ + TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_Fetched value)? fetched, }) { return fetched?.call(this); @@ -157,6 +333,7 @@ class _$FetchedImpl implements _Fetched { @override @optionalTypeArgs TResult maybeMap({ + TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_Fetched value)? fetched, required TResult orElse(), }) { @@ -177,6 +354,8 @@ mixin _$ProductAnalyticLoaderState { Option get failureOptionProductAnalytic => throw _privateConstructorUsedError; bool get isFetching => throw _privateConstructorUsedError; + DateTime get dateFrom => throw _privateConstructorUsedError; + DateTime get dateTo => throw _privateConstructorUsedError; /// Create a copy of ProductAnalyticLoaderState /// with the given fields replaced by the non-null parameter values. @@ -200,6 +379,8 @@ abstract class $ProductAnalyticLoaderStateCopyWith<$Res> { ProductAnalytic productAnalytic, Option failureOptionProductAnalytic, bool isFetching, + DateTime dateFrom, + DateTime dateTo, }); $ProductAnalyticCopyWith<$Res> get productAnalytic; @@ -226,6 +407,8 @@ class _$ProductAnalyticLoaderStateCopyWithImpl< Object? productAnalytic = null, Object? failureOptionProductAnalytic = null, Object? isFetching = null, + Object? dateFrom = null, + Object? dateTo = null, }) { return _then( _value.copyWith( @@ -241,6 +424,14 @@ class _$ProductAnalyticLoaderStateCopyWithImpl< ? _value.isFetching : isFetching // ignore: cast_nullable_to_non_nullable 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, ); @@ -270,6 +461,8 @@ abstract class _$$ProductAnalyticLoaderStateImplCopyWith<$Res> ProductAnalytic productAnalytic, Option failureOptionProductAnalytic, bool isFetching, + DateTime dateFrom, + DateTime dateTo, }); @override @@ -297,6 +490,8 @@ class __$$ProductAnalyticLoaderStateImplCopyWithImpl<$Res> Object? productAnalytic = null, Object? failureOptionProductAnalytic = null, Object? isFetching = null, + Object? dateFrom = null, + Object? dateTo = null, }) { return _then( _$ProductAnalyticLoaderStateImpl( @@ -312,6 +507,14 @@ class __$$ProductAnalyticLoaderStateImplCopyWithImpl<$Res> ? _value.isFetching : isFetching // ignore: cast_nullable_to_non_nullable 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, ), ); } @@ -324,6 +527,8 @@ class _$ProductAnalyticLoaderStateImpl implements _ProductAnalyticLoaderState { required this.productAnalytic, required this.failureOptionProductAnalytic, this.isFetching = false, + required this.dateFrom, + required this.dateTo, }); @override @@ -333,10 +538,14 @@ class _$ProductAnalyticLoaderStateImpl implements _ProductAnalyticLoaderState { @override @JsonKey() final bool isFetching; + @override + final DateTime dateFrom; + @override + final DateTime dateTo; @override String toString() { - return 'ProductAnalyticLoaderState(productAnalytic: $productAnalytic, failureOptionProductAnalytic: $failureOptionProductAnalytic, isFetching: $isFetching)'; + return 'ProductAnalyticLoaderState(productAnalytic: $productAnalytic, failureOptionProductAnalytic: $failureOptionProductAnalytic, isFetching: $isFetching, dateFrom: $dateFrom, dateTo: $dateTo)'; } @override @@ -353,7 +562,10 @@ class _$ProductAnalyticLoaderStateImpl implements _ProductAnalyticLoaderState { other.failureOptionProductAnalytic == failureOptionProductAnalytic) && (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 @@ -362,6 +574,8 @@ class _$ProductAnalyticLoaderStateImpl implements _ProductAnalyticLoaderState { productAnalytic, failureOptionProductAnalytic, isFetching, + dateFrom, + dateTo, ); /// Create a copy of ProductAnalyticLoaderState @@ -382,6 +596,8 @@ abstract class _ProductAnalyticLoaderState required final ProductAnalytic productAnalytic, required final Option failureOptionProductAnalytic, final bool isFetching, + required final DateTime dateFrom, + required final DateTime dateTo, }) = _$ProductAnalyticLoaderStateImpl; @override @@ -390,6 +606,10 @@ abstract class _ProductAnalyticLoaderState Option get failureOptionProductAnalytic; @override bool get isFetching; + @override + DateTime get dateFrom; + @override + DateTime get dateTo; /// Create a copy of ProductAnalyticLoaderState /// with the given fields replaced by the non-null parameter values. diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart index 58e9c7f..b707a93 100644 --- a/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart @@ -2,5 +2,9 @@ part of 'product_analytic_loader_bloc.dart'; @freezed class ProductAnalyticLoaderEvent with _$ProductAnalyticLoaderEvent { + const factory ProductAnalyticLoaderEvent.rangeDateChanged( + DateTime dateFrom, + DateTime dateTo, + ) = _RangeDateChanged; const factory ProductAnalyticLoaderEvent.fetched() = _Fetched; } diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart index 23dfa16..94b349a 100644 --- a/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart @@ -6,10 +6,14 @@ class ProductAnalyticLoaderState with _$ProductAnalyticLoaderState { required ProductAnalytic productAnalytic, required Option failureOptionProductAnalytic, @Default(false) bool isFetching, + required DateTime dateFrom, + required DateTime dateTo, }) = _ProductAnalyticLoaderState; factory ProductAnalyticLoaderState.initial() => ProductAnalyticLoaderState( productAnalytic: ProductAnalytic.empty(), failureOptionProductAnalytic: none(), + dateFrom: DateTime.now().subtract(const Duration(days: 30)), + dateTo: DateTime.now(), ); } diff --git a/lib/domain/analytic/analytic.freezed.dart b/lib/domain/analytic/analytic.freezed.dart index ac7fd5b..5cd5ff1 100644 --- a/lib/domain/analytic/analytic.freezed.dart +++ b/lib/domain/analytic/analytic.freezed.dart @@ -5972,7 +5972,7 @@ mixin _$ProductAnalyticData { String get categoryId => throw _privateConstructorUsedError; String get categoryName => throw _privateConstructorUsedError; int get quantitySold => throw _privateConstructorUsedError; - double get revenue => throw _privateConstructorUsedError; + int get revenue => throw _privateConstructorUsedError; double get averagePrice => throw _privateConstructorUsedError; int get orderCount => throw _privateConstructorUsedError; @@ -5996,7 +5996,7 @@ abstract class $ProductAnalyticDataCopyWith<$Res> { String categoryId, String categoryName, int quantitySold, - double revenue, + int revenue, double averagePrice, int orderCount, }); @@ -6051,7 +6051,7 @@ class _$ProductAnalyticDataCopyWithImpl<$Res, $Val extends ProductAnalyticData> revenue: null == revenue ? _value.revenue : revenue // ignore: cast_nullable_to_non_nullable - as double, + as int, averagePrice: null == averagePrice ? _value.averagePrice : averagePrice // ignore: cast_nullable_to_non_nullable @@ -6081,7 +6081,7 @@ abstract class _$$ProductAnalyticDataImplCopyWith<$Res> String categoryId, String categoryName, int quantitySold, - double revenue, + int revenue, double averagePrice, int orderCount, }); @@ -6135,7 +6135,7 @@ class __$$ProductAnalyticDataImplCopyWithImpl<$Res> revenue: null == revenue ? _value.revenue : revenue // ignore: cast_nullable_to_non_nullable - as double, + as int, averagePrice: null == averagePrice ? _value.averagePrice : averagePrice // ignore: cast_nullable_to_non_nullable @@ -6174,7 +6174,7 @@ class _$ProductAnalyticDataImpl implements _ProductAnalyticData { @override final int quantitySold; @override - final double revenue; + final int revenue; @override final double averagePrice; @override @@ -6239,7 +6239,7 @@ abstract class _ProductAnalyticData implements ProductAnalyticData { required final String categoryId, required final String categoryName, required final int quantitySold, - required final double revenue, + required final int revenue, required final double averagePrice, required final int orderCount, }) = _$ProductAnalyticDataImpl; @@ -6255,7 +6255,7 @@ abstract class _ProductAnalyticData implements ProductAnalyticData { @override int get quantitySold; @override - double get revenue; + int get revenue; @override double get averagePrice; @override diff --git a/lib/domain/analytic/entities/product_analytic_entity.dart b/lib/domain/analytic/entities/product_analytic_entity.dart index 1b57062..33b8c3a 100644 --- a/lib/domain/analytic/entities/product_analytic_entity.dart +++ b/lib/domain/analytic/entities/product_analytic_entity.dart @@ -27,7 +27,7 @@ class ProductAnalyticData with _$ProductAnalyticData { required String categoryId, required String categoryName, required int quantitySold, - required double revenue, + required int revenue, required double averagePrice, required int orderCount, }) = _ProductAnalyticData; @@ -38,7 +38,7 @@ class ProductAnalyticData with _$ProductAnalyticData { categoryId: '', categoryName: '', quantitySold: 0, - revenue: 0.0, + revenue: 0, averagePrice: 0.0, orderCount: 0, ); diff --git a/lib/infrastructure/analytic/analytic_dtos.freezed.dart b/lib/infrastructure/analytic/analytic_dtos.freezed.dart index 199c7a8..f5f56fd 100644 --- a/lib/infrastructure/analytic/analytic_dtos.freezed.dart +++ b/lib/infrastructure/analytic/analytic_dtos.freezed.dart @@ -6661,14 +6661,15 @@ ProductAnalyticDto _$ProductAnalyticDtoFromJson(Map json) { /// @nodoc mixin _$ProductAnalyticDto { @JsonKey(name: 'organization_id') - String get organizationId => throw _privateConstructorUsedError; + String? get organizationId => throw _privateConstructorUsedError; @JsonKey(name: 'outlet_id') - String get outletId => throw _privateConstructorUsedError; + String? get outletId => throw _privateConstructorUsedError; @JsonKey(name: 'date_from') - String get dateFrom => throw _privateConstructorUsedError; + String? get dateFrom => throw _privateConstructorUsedError; @JsonKey(name: 'date_to') - String get dateTo => throw _privateConstructorUsedError; - List get data => throw _privateConstructorUsedError; + String? get dateTo => throw _privateConstructorUsedError; + @JsonKey(name: 'data') + List? get data => throw _privateConstructorUsedError; /// Serializes this ProductAnalyticDto to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -6688,11 +6689,11 @@ abstract class $ProductAnalyticDtoCopyWith<$Res> { ) = _$ProductAnalyticDtoCopyWithImpl<$Res, ProductAnalyticDto>; @useResult $Res call({ - @JsonKey(name: 'organization_id') String organizationId, - @JsonKey(name: 'outlet_id') String outletId, - @JsonKey(name: 'date_from') String dateFrom, - @JsonKey(name: 'date_to') String dateTo, - List data, + @JsonKey(name: 'organization_id') String? organizationId, + @JsonKey(name: 'outlet_id') String? outletId, + @JsonKey(name: 'date_from') String? dateFrom, + @JsonKey(name: 'date_to') String? dateTo, + @JsonKey(name: 'data') List? data, }); } @@ -6711,34 +6712,34 @@ class _$ProductAnalyticDtoCopyWithImpl<$Res, $Val extends ProductAnalyticDto> @pragma('vm:prefer-inline') @override $Res call({ - Object? organizationId = null, - Object? outletId = null, - Object? dateFrom = null, - Object? dateTo = null, - Object? data = null, + Object? organizationId = freezed, + Object? outletId = freezed, + Object? dateFrom = freezed, + Object? dateTo = freezed, + Object? data = freezed, }) { return _then( _value.copyWith( - organizationId: null == organizationId + organizationId: freezed == organizationId ? _value.organizationId : organizationId // ignore: cast_nullable_to_non_nullable - as String, - outletId: null == outletId + as String?, + outletId: freezed == outletId ? _value.outletId : outletId // ignore: cast_nullable_to_non_nullable - as String, - dateFrom: null == dateFrom + as String?, + dateFrom: freezed == dateFrom ? _value.dateFrom : dateFrom // ignore: cast_nullable_to_non_nullable - as String, - dateTo: null == dateTo + as String?, + dateTo: freezed == dateTo ? _value.dateTo : dateTo // ignore: cast_nullable_to_non_nullable - as String, - data: null == data + as String?, + data: freezed == data ? _value.data : data // ignore: cast_nullable_to_non_nullable - as List, + as List?, ) as $Val, ); @@ -6755,11 +6756,11 @@ abstract class _$$ProductAnalyticDtoImplCopyWith<$Res> @override @useResult $Res call({ - @JsonKey(name: 'organization_id') String organizationId, - @JsonKey(name: 'outlet_id') String outletId, - @JsonKey(name: 'date_from') String dateFrom, - @JsonKey(name: 'date_to') String dateTo, - List data, + @JsonKey(name: 'organization_id') String? organizationId, + @JsonKey(name: 'outlet_id') String? outletId, + @JsonKey(name: 'date_from') String? dateFrom, + @JsonKey(name: 'date_to') String? dateTo, + @JsonKey(name: 'data') List? data, }); } @@ -6777,34 +6778,34 @@ class __$$ProductAnalyticDtoImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? organizationId = null, - Object? outletId = null, - Object? dateFrom = null, - Object? dateTo = null, - Object? data = null, + Object? organizationId = freezed, + Object? outletId = freezed, + Object? dateFrom = freezed, + Object? dateTo = freezed, + Object? data = freezed, }) { return _then( _$ProductAnalyticDtoImpl( - organizationId: null == organizationId + organizationId: freezed == organizationId ? _value.organizationId : organizationId // ignore: cast_nullable_to_non_nullable - as String, - outletId: null == outletId + as String?, + outletId: freezed == outletId ? _value.outletId : outletId // ignore: cast_nullable_to_non_nullable - as String, - dateFrom: null == dateFrom + as String?, + dateFrom: freezed == dateFrom ? _value.dateFrom : dateFrom // ignore: cast_nullable_to_non_nullable - as String, - dateTo: null == dateTo + as String?, + dateTo: freezed == dateTo ? _value.dateTo : dateTo // ignore: cast_nullable_to_non_nullable - as String, - data: null == data + as String?, + data: freezed == data ? _value._data : data // ignore: cast_nullable_to_non_nullable - as List, + as List?, ), ); } @@ -6814,11 +6815,11 @@ class __$$ProductAnalyticDtoImplCopyWithImpl<$Res> @JsonSerializable() class _$ProductAnalyticDtoImpl extends _ProductAnalyticDto { const _$ProductAnalyticDtoImpl({ - @JsonKey(name: 'organization_id') required this.organizationId, - @JsonKey(name: 'outlet_id') required this.outletId, - @JsonKey(name: 'date_from') required this.dateFrom, - @JsonKey(name: 'date_to') required this.dateTo, - required final List data, + @JsonKey(name: 'organization_id') this.organizationId, + @JsonKey(name: 'outlet_id') this.outletId, + @JsonKey(name: 'date_from') this.dateFrom, + @JsonKey(name: 'date_to') this.dateTo, + @JsonKey(name: 'data') final List? data, }) : _data = data, super._(); @@ -6827,22 +6828,25 @@ class _$ProductAnalyticDtoImpl extends _ProductAnalyticDto { @override @JsonKey(name: 'organization_id') - final String organizationId; + final String? organizationId; @override @JsonKey(name: 'outlet_id') - final String outletId; + final String? outletId; @override @JsonKey(name: 'date_from') - final String dateFrom; + final String? dateFrom; @override @JsonKey(name: 'date_to') - final String dateTo; - final List _data; + final String? dateTo; + final List? _data; @override - List get data { + @JsonKey(name: 'data') + List? get data { + final value = _data; + if (value == null) return null; if (_data is EqualUnmodifiableListView) return _data; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_data); + return EqualUnmodifiableListView(value); } @override @@ -6895,11 +6899,11 @@ class _$ProductAnalyticDtoImpl extends _ProductAnalyticDto { abstract class _ProductAnalyticDto extends ProductAnalyticDto { const factory _ProductAnalyticDto({ - @JsonKey(name: 'organization_id') required final String organizationId, - @JsonKey(name: 'outlet_id') required final String outletId, - @JsonKey(name: 'date_from') required final String dateFrom, - @JsonKey(name: 'date_to') required final String dateTo, - required final List data, + @JsonKey(name: 'organization_id') final String? organizationId, + @JsonKey(name: 'outlet_id') final String? outletId, + @JsonKey(name: 'date_from') final String? dateFrom, + @JsonKey(name: 'date_to') final String? dateTo, + @JsonKey(name: 'data') final List? data, }) = _$ProductAnalyticDtoImpl; const _ProductAnalyticDto._() : super._(); @@ -6908,18 +6912,19 @@ abstract class _ProductAnalyticDto extends ProductAnalyticDto { @override @JsonKey(name: 'organization_id') - String get organizationId; + String? get organizationId; @override @JsonKey(name: 'outlet_id') - String get outletId; + String? get outletId; @override @JsonKey(name: 'date_from') - String get dateFrom; + String? get dateFrom; @override @JsonKey(name: 'date_to') - String get dateTo; + String? get dateTo; @override - List get data; + @JsonKey(name: 'data') + List? get data; /// Create a copy of ProductAnalyticDto /// with the given fields replaced by the non-null parameter values. @@ -6938,20 +6943,21 @@ ProductAnalyticDataDto _$ProductAnalyticDataDtoFromJson( /// @nodoc mixin _$ProductAnalyticDataDto { @JsonKey(name: 'product_id') - String get productId => throw _privateConstructorUsedError; + String? get productId => throw _privateConstructorUsedError; @JsonKey(name: 'product_name') - String get productName => throw _privateConstructorUsedError; + String? get productName => throw _privateConstructorUsedError; @JsonKey(name: 'category_id') - String get categoryId => throw _privateConstructorUsedError; + String? get categoryId => throw _privateConstructorUsedError; @JsonKey(name: 'category_name') - String get categoryName => throw _privateConstructorUsedError; + String? get categoryName => throw _privateConstructorUsedError; @JsonKey(name: 'quantity_sold') - int get quantitySold => throw _privateConstructorUsedError; - double get revenue => throw _privateConstructorUsedError; + int? get quantitySold => throw _privateConstructorUsedError; + @JsonKey(name: 'revenue') + int? get revenue => throw _privateConstructorUsedError; @JsonKey(name: 'average_price') - double get averagePrice => throw _privateConstructorUsedError; + double? get averagePrice => throw _privateConstructorUsedError; @JsonKey(name: 'order_count') - int get orderCount => throw _privateConstructorUsedError; + int? get orderCount => throw _privateConstructorUsedError; /// Serializes this ProductAnalyticDataDto to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -6971,14 +6977,14 @@ abstract class $ProductAnalyticDataDtoCopyWith<$Res> { ) = _$ProductAnalyticDataDtoCopyWithImpl<$Res, ProductAnalyticDataDto>; @useResult $Res call({ - @JsonKey(name: 'product_id') String productId, - @JsonKey(name: 'product_name') String productName, - @JsonKey(name: 'category_id') String categoryId, - @JsonKey(name: 'category_name') String categoryName, - @JsonKey(name: 'quantity_sold') int quantitySold, - double revenue, - @JsonKey(name: 'average_price') double averagePrice, - @JsonKey(name: 'order_count') int orderCount, + @JsonKey(name: 'product_id') String? productId, + @JsonKey(name: 'product_name') String? productName, + @JsonKey(name: 'category_id') String? categoryId, + @JsonKey(name: 'category_name') String? categoryName, + @JsonKey(name: 'quantity_sold') int? quantitySold, + @JsonKey(name: 'revenue') int? revenue, + @JsonKey(name: 'average_price') double? averagePrice, + @JsonKey(name: 'order_count') int? orderCount, }); } @@ -7000,49 +7006,49 @@ class _$ProductAnalyticDataDtoCopyWithImpl< @pragma('vm:prefer-inline') @override $Res call({ - Object? productId = null, - Object? productName = null, - Object? categoryId = null, - Object? categoryName = null, - Object? quantitySold = null, - Object? revenue = null, - Object? averagePrice = null, - Object? orderCount = null, + Object? productId = freezed, + Object? productName = freezed, + Object? categoryId = freezed, + Object? categoryName = freezed, + Object? quantitySold = freezed, + Object? revenue = freezed, + Object? averagePrice = freezed, + Object? orderCount = freezed, }) { return _then( _value.copyWith( - productId: null == productId + productId: freezed == productId ? _value.productId : productId // ignore: cast_nullable_to_non_nullable - as String, - productName: null == productName + as String?, + productName: freezed == productName ? _value.productName : productName // ignore: cast_nullable_to_non_nullable - as String, - categoryId: null == categoryId + as String?, + categoryId: freezed == categoryId ? _value.categoryId : categoryId // ignore: cast_nullable_to_non_nullable - as String, - categoryName: null == categoryName + as String?, + categoryName: freezed == categoryName ? _value.categoryName : categoryName // ignore: cast_nullable_to_non_nullable - as String, - quantitySold: null == quantitySold + as String?, + quantitySold: freezed == quantitySold ? _value.quantitySold : quantitySold // ignore: cast_nullable_to_non_nullable - as int, - revenue: null == revenue + as int?, + revenue: freezed == revenue ? _value.revenue : revenue // ignore: cast_nullable_to_non_nullable - as double, - averagePrice: null == averagePrice + as int?, + averagePrice: freezed == averagePrice ? _value.averagePrice : averagePrice // ignore: cast_nullable_to_non_nullable - as double, - orderCount: null == orderCount + as double?, + orderCount: freezed == orderCount ? _value.orderCount : orderCount // ignore: cast_nullable_to_non_nullable - as int, + as int?, ) as $Val, ); @@ -7059,14 +7065,14 @@ abstract class _$$ProductAnalyticDataDtoImplCopyWith<$Res> @override @useResult $Res call({ - @JsonKey(name: 'product_id') String productId, - @JsonKey(name: 'product_name') String productName, - @JsonKey(name: 'category_id') String categoryId, - @JsonKey(name: 'category_name') String categoryName, - @JsonKey(name: 'quantity_sold') int quantitySold, - double revenue, - @JsonKey(name: 'average_price') double averagePrice, - @JsonKey(name: 'order_count') int orderCount, + @JsonKey(name: 'product_id') String? productId, + @JsonKey(name: 'product_name') String? productName, + @JsonKey(name: 'category_id') String? categoryId, + @JsonKey(name: 'category_name') String? categoryName, + @JsonKey(name: 'quantity_sold') int? quantitySold, + @JsonKey(name: 'revenue') int? revenue, + @JsonKey(name: 'average_price') double? averagePrice, + @JsonKey(name: 'order_count') int? orderCount, }); } @@ -7085,49 +7091,49 @@ class __$$ProductAnalyticDataDtoImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? productId = null, - Object? productName = null, - Object? categoryId = null, - Object? categoryName = null, - Object? quantitySold = null, - Object? revenue = null, - Object? averagePrice = null, - Object? orderCount = null, + Object? productId = freezed, + Object? productName = freezed, + Object? categoryId = freezed, + Object? categoryName = freezed, + Object? quantitySold = freezed, + Object? revenue = freezed, + Object? averagePrice = freezed, + Object? orderCount = freezed, }) { return _then( _$ProductAnalyticDataDtoImpl( - productId: null == productId + productId: freezed == productId ? _value.productId : productId // ignore: cast_nullable_to_non_nullable - as String, - productName: null == productName + as String?, + productName: freezed == productName ? _value.productName : productName // ignore: cast_nullable_to_non_nullable - as String, - categoryId: null == categoryId + as String?, + categoryId: freezed == categoryId ? _value.categoryId : categoryId // ignore: cast_nullable_to_non_nullable - as String, - categoryName: null == categoryName + as String?, + categoryName: freezed == categoryName ? _value.categoryName : categoryName // ignore: cast_nullable_to_non_nullable - as String, - quantitySold: null == quantitySold + as String?, + quantitySold: freezed == quantitySold ? _value.quantitySold : quantitySold // ignore: cast_nullable_to_non_nullable - as int, - revenue: null == revenue + as int?, + revenue: freezed == revenue ? _value.revenue : revenue // ignore: cast_nullable_to_non_nullable - as double, - averagePrice: null == averagePrice + as int?, + averagePrice: freezed == averagePrice ? _value.averagePrice : averagePrice // ignore: cast_nullable_to_non_nullable - as double, - orderCount: null == orderCount + as double?, + orderCount: freezed == orderCount ? _value.orderCount : orderCount // ignore: cast_nullable_to_non_nullable - as int, + as int?, ), ); } @@ -7137,14 +7143,14 @@ class __$$ProductAnalyticDataDtoImplCopyWithImpl<$Res> @JsonSerializable() class _$ProductAnalyticDataDtoImpl extends _ProductAnalyticDataDto { const _$ProductAnalyticDataDtoImpl({ - @JsonKey(name: 'product_id') required this.productId, - @JsonKey(name: 'product_name') required this.productName, - @JsonKey(name: 'category_id') required this.categoryId, - @JsonKey(name: 'category_name') required this.categoryName, - @JsonKey(name: 'quantity_sold') required this.quantitySold, - required this.revenue, - @JsonKey(name: 'average_price') required this.averagePrice, - @JsonKey(name: 'order_count') required this.orderCount, + @JsonKey(name: 'product_id') this.productId, + @JsonKey(name: 'product_name') this.productName, + @JsonKey(name: 'category_id') this.categoryId, + @JsonKey(name: 'category_name') this.categoryName, + @JsonKey(name: 'quantity_sold') this.quantitySold, + @JsonKey(name: 'revenue') this.revenue, + @JsonKey(name: 'average_price') this.averagePrice, + @JsonKey(name: 'order_count') this.orderCount, }) : super._(); factory _$ProductAnalyticDataDtoImpl.fromJson(Map json) => @@ -7152,27 +7158,28 @@ class _$ProductAnalyticDataDtoImpl extends _ProductAnalyticDataDto { @override @JsonKey(name: 'product_id') - final String productId; + final String? productId; @override @JsonKey(name: 'product_name') - final String productName; + final String? productName; @override @JsonKey(name: 'category_id') - final String categoryId; + final String? categoryId; @override @JsonKey(name: 'category_name') - final String categoryName; + final String? categoryName; @override @JsonKey(name: 'quantity_sold') - final int quantitySold; + final int? quantitySold; @override - final double revenue; + @JsonKey(name: 'revenue') + final int? revenue; @override @JsonKey(name: 'average_price') - final double averagePrice; + final double? averagePrice; @override @JsonKey(name: 'order_count') - final int orderCount; + final int? orderCount; @override String toString() { @@ -7235,14 +7242,14 @@ class _$ProductAnalyticDataDtoImpl extends _ProductAnalyticDataDto { abstract class _ProductAnalyticDataDto extends ProductAnalyticDataDto { const factory _ProductAnalyticDataDto({ - @JsonKey(name: 'product_id') required final String productId, - @JsonKey(name: 'product_name') required final String productName, - @JsonKey(name: 'category_id') required final String categoryId, - @JsonKey(name: 'category_name') required final String categoryName, - @JsonKey(name: 'quantity_sold') required final int quantitySold, - required final double revenue, - @JsonKey(name: 'average_price') required final double averagePrice, - @JsonKey(name: 'order_count') required final int orderCount, + @JsonKey(name: 'product_id') final String? productId, + @JsonKey(name: 'product_name') final String? productName, + @JsonKey(name: 'category_id') final String? categoryId, + @JsonKey(name: 'category_name') final String? categoryName, + @JsonKey(name: 'quantity_sold') final int? quantitySold, + @JsonKey(name: 'revenue') final int? revenue, + @JsonKey(name: 'average_price') final double? averagePrice, + @JsonKey(name: 'order_count') final int? orderCount, }) = _$ProductAnalyticDataDtoImpl; const _ProductAnalyticDataDto._() : super._(); @@ -7251,27 +7258,28 @@ abstract class _ProductAnalyticDataDto extends ProductAnalyticDataDto { @override @JsonKey(name: 'product_id') - String get productId; + String? get productId; @override @JsonKey(name: 'product_name') - String get productName; + String? get productName; @override @JsonKey(name: 'category_id') - String get categoryId; + String? get categoryId; @override @JsonKey(name: 'category_name') - String get categoryName; + String? get categoryName; @override @JsonKey(name: 'quantity_sold') - int get quantitySold; + int? get quantitySold; @override - double get revenue; + @JsonKey(name: 'revenue') + int? get revenue; @override @JsonKey(name: 'average_price') - double get averagePrice; + double? get averagePrice; @override @JsonKey(name: 'order_count') - int get orderCount; + int? get orderCount; /// Create a copy of ProductAnalyticDataDto /// with the given fields replaced by the non-null parameter values. diff --git a/lib/infrastructure/analytic/analytic_dtos.g.dart b/lib/infrastructure/analytic/analytic_dtos.g.dart index f29e863..fbdd5a6 100644 --- a/lib/infrastructure/analytic/analytic_dtos.g.dart +++ b/lib/infrastructure/analytic/analytic_dtos.g.dart @@ -521,12 +521,12 @@ Map _$$DashboardRecentSaleDtoImplToJson( _$ProductAnalyticDtoImpl _$$ProductAnalyticDtoImplFromJson( Map json, ) => _$ProductAnalyticDtoImpl( - organizationId: json['organization_id'] as String, - outletId: json['outlet_id'] as String, - dateFrom: json['date_from'] as String, - dateTo: json['date_to'] as String, - data: (json['data'] as List) - .map((e) => ProductAnalyticDataDto.fromJson(e as Map)) + organizationId: json['organization_id'] as String?, + outletId: json['outlet_id'] as String?, + dateFrom: json['date_from'] as String?, + dateTo: json['date_to'] as String?, + data: (json['data'] as List?) + ?.map((e) => ProductAnalyticDataDto.fromJson(e as Map)) .toList(), ); @@ -543,14 +543,14 @@ Map _$$ProductAnalyticDtoImplToJson( _$ProductAnalyticDataDtoImpl _$$ProductAnalyticDataDtoImplFromJson( Map json, ) => _$ProductAnalyticDataDtoImpl( - productId: json['product_id'] as String, - productName: json['product_name'] as String, - categoryId: json['category_id'] as String, - categoryName: json['category_name'] as String, - quantitySold: (json['quantity_sold'] as num).toInt(), - revenue: (json['revenue'] as num).toDouble(), - averagePrice: (json['average_price'] as num).toDouble(), - orderCount: (json['order_count'] as num).toInt(), + productId: json['product_id'] as String?, + productName: json['product_name'] as String?, + categoryId: json['category_id'] as String?, + categoryName: json['category_name'] as String?, + quantitySold: (json['quantity_sold'] as num?)?.toInt(), + revenue: (json['revenue'] as num?)?.toInt(), + averagePrice: (json['average_price'] as num?)?.toDouble(), + orderCount: (json['order_count'] as num?)?.toInt(), ); Map _$$ProductAnalyticDataDtoImplToJson( diff --git a/lib/infrastructure/analytic/dto/product_analytic_dto.dart b/lib/infrastructure/analytic/dto/product_analytic_dto.dart index 68eb722..b143e1e 100644 --- a/lib/infrastructure/analytic/dto/product_analytic_dto.dart +++ b/lib/infrastructure/analytic/dto/product_analytic_dto.dart @@ -5,22 +5,22 @@ class ProductAnalyticDto with _$ProductAnalyticDto { const ProductAnalyticDto._(); const factory ProductAnalyticDto({ - @JsonKey(name: 'organization_id') required String organizationId, - @JsonKey(name: 'outlet_id') required String outletId, - @JsonKey(name: 'date_from') required String dateFrom, - @JsonKey(name: 'date_to') required String dateTo, - required List data, + @JsonKey(name: 'organization_id') String? organizationId, + @JsonKey(name: 'outlet_id') String? outletId, + @JsonKey(name: 'date_from') String? dateFrom, + @JsonKey(name: 'date_to') String? dateTo, + @JsonKey(name: 'data') List? data, }) = _ProductAnalyticDto; factory ProductAnalyticDto.fromJson(Map json) => _$ProductAnalyticDtoFromJson(json); ProductAnalytic toDomain() => ProductAnalytic( - organizationId: organizationId, - outletId: outletId, - dateFrom: dateFrom, - dateTo: dateTo, - data: data.map((e) => e.toDomain()).toList(), + organizationId: organizationId ?? "", + outletId: outletId ?? "", + dateFrom: dateFrom ?? "", + dateTo: dateTo ?? "", + data: data?.map((e) => e.toDomain()).toList() ?? [], ); } @@ -29,27 +29,27 @@ class ProductAnalyticDataDto with _$ProductAnalyticDataDto { const ProductAnalyticDataDto._(); const factory ProductAnalyticDataDto({ - @JsonKey(name: 'product_id') required String productId, - @JsonKey(name: 'product_name') required String productName, - @JsonKey(name: 'category_id') required String categoryId, - @JsonKey(name: 'category_name') required String categoryName, - @JsonKey(name: 'quantity_sold') required int quantitySold, - required double revenue, - @JsonKey(name: 'average_price') required double averagePrice, - @JsonKey(name: 'order_count') required int orderCount, + @JsonKey(name: 'product_id') String? productId, + @JsonKey(name: 'product_name') String? productName, + @JsonKey(name: 'category_id') String? categoryId, + @JsonKey(name: 'category_name') String? categoryName, + @JsonKey(name: 'quantity_sold') int? quantitySold, + @JsonKey(name: 'revenue') int? revenue, + @JsonKey(name: 'average_price') double? averagePrice, + @JsonKey(name: 'order_count') int? orderCount, }) = _ProductAnalyticDataDto; factory ProductAnalyticDataDto.fromJson(Map json) => _$ProductAnalyticDataDtoFromJson(json); ProductAnalyticData toDomain() => ProductAnalyticData( - productId: productId, - productName: productName, - categoryId: categoryId, - categoryName: categoryName, - quantitySold: quantitySold, - revenue: revenue, - averagePrice: averagePrice, - orderCount: orderCount, + productId: productId ?? "", + productName: productName ?? "", + categoryId: categoryId ?? "", + categoryName: categoryName ?? "", + quantitySold: quantitySold ?? 0, + revenue: revenue ?? 0, + averagePrice: averagePrice ?? 0, + orderCount: orderCount ?? 0, ); } diff --git a/lib/presentation/pages/product/product_analytic/product_analytic_page.dart b/lib/presentation/pages/product/product_analytic/product_analytic_page.dart index 8d3e623..853c4c2 100644 --- a/lib/presentation/pages/product/product_analytic/product_analytic_page.dart +++ b/lib/presentation/pages/product/product_analytic/product_analytic_page.dart @@ -1,16 +1,28 @@ import 'package:flutter/material.dart'; import 'package:auto_route/auto_route.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart'; import '../../../../common/theme/theme.dart'; import '../../../../domain/analytic/analytic.dart'; +import '../../../../injection.dart'; import '../../../components/appbar/appbar.dart'; +import '../../../components/field/date_range_picker_field.dart'; @RoutePage() -class ProductAnalyticPage extends StatefulWidget { +class ProductAnalyticPage extends StatefulWidget implements AutoRouteWrapper { const ProductAnalyticPage({super.key}); @override State createState() => _ProductAnalyticPageState(); + + @override + Widget wrappedRoute(BuildContext context) => BlocProvider( + create: (context) => + getIt() + ..add(ProductAnalyticLoaderEvent.fetched()), + child: this, + ); } class _ProductAnalyticPageState extends State @@ -20,66 +32,6 @@ class _ProductAnalyticPageState extends State late Animation _fadeAnimation; late Animation _slideAnimation; - // Sample data untuk demo - final ProductAnalytic sampleData = ProductAnalytic( - organizationId: "org_123", - outletId: "outlet_456", - dateFrom: "2024-01-01", - dateTo: "2024-01-31", - data: [ - ProductAnalyticData( - productId: "prod_1", - productName: "Nasi Goreng Spesial", - categoryId: "cat_1", - categoryName: "Makanan Utama", - quantitySold: 145, - revenue: 2175000.0, - averagePrice: 15000.0, - orderCount: 98, - ), - ProductAnalyticData( - productId: "prod_2", - productName: "Es Teh Manis", - categoryId: "cat_2", - categoryName: "Minuman", - quantitySold: 230, - revenue: 1150000.0, - averagePrice: 5000.0, - orderCount: 180, - ), - ProductAnalyticData( - productId: "prod_3", - productName: "Ayam Bakar", - categoryId: "cat_1", - categoryName: "Makanan Utama", - quantitySold: 89, - revenue: 2225000.0, - averagePrice: 25000.0, - orderCount: 75, - ), - ProductAnalyticData( - productId: "prod_4", - productName: "Cappuccino", - categoryId: "cat_2", - categoryName: "Minuman", - quantitySold: 67, - revenue: 1005000.0, - averagePrice: 15000.0, - orderCount: 52, - ), - ProductAnalyticData( - productId: "prod_5", - productName: "Pisang Goreng", - categoryId: "cat_3", - categoryName: "Snack", - quantitySold: 156, - revenue: 780000.0, - averagePrice: 5000.0, - orderCount: 134, - ), - ], - ); - @override void initState() { super.initState(); @@ -126,13 +78,52 @@ class _ProductAnalyticPageState extends State Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.background, - body: CustomScrollView( - physics: const BouncingScrollPhysics(), - slivers: [ - _buildSliverAppBar(), - _buildSummarySection(), - _buildProductsList(), - ], + body: BlocListener( + listenWhen: (previous, current) => + previous.dateFrom != current.dateFrom || + previous.dateTo != current.dateTo, + listener: (context, state) { + context.read().add( + ProductAnalyticLoaderEvent.fetched(), + ); + }, + child: + BlocBuilder( + builder: (context, state) { + return CustomScrollView( + physics: const BouncingScrollPhysics(), + slivers: [ + _buildSliverAppBar(), + SliverToBoxAdapter( + child: SlideTransition( + position: _slideAnimation, + child: FadeTransition( + opacity: _fadeAnimation, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: DateRangePickerField( + maxDate: DateTime.now(), + startDate: state.dateFrom, + endDate: state.dateTo, + onChanged: (startDate, endDate) { + context.read().add( + ProductAnalyticLoaderEvent.rangeDateChanged( + startDate!, + endDate!, + ), + ); + }, + ), + ), + ), + ), + ), + _buildSummarySection(state.productAnalytic), + _buildProductsList(state.productAnalytic), + ], + ); + }, + ), ), ); } @@ -161,7 +152,7 @@ class _ProductAnalyticPageState extends State } // SUMMARY SECTION - Widget _buildSummarySection() { + Widget _buildSummarySection(ProductAnalytic productAnalytic) { return SliverToBoxAdapter( child: FadeTransition( opacity: _fadeAnimation, @@ -169,7 +160,7 @@ class _ProductAnalyticPageState extends State position: _slideAnimation, child: Container( margin: const EdgeInsets.all(16), - child: _buildSummaryCards(sampleData.data), + child: _buildSummaryCards(productAnalytic.data), ), ), ), @@ -177,7 +168,7 @@ class _ProductAnalyticPageState extends State } // PRODUCTS LIST - Widget _buildProductsList() { + Widget _buildProductsList(ProductAnalytic productAnalytic) { return SliverPadding( padding: const EdgeInsets.all(16), sliver: SliverList( @@ -198,12 +189,16 @@ class _ProductAnalyticPageState extends State offset: Offset(0, 50 * (1 - animValue)), child: Opacity( opacity: animValue, - child: _buildProductCard(sampleData.data[index], index), + child: _buildProductCard( + productAnalytic, + productAnalytic.data[index], + index, + ), ), ); }, ); - }, childCount: sampleData.data.length), + }, childCount: productAnalytic.data.length), ), ); } @@ -330,7 +325,11 @@ class _ProductAnalyticPageState extends State } // PRODUCT CARD - NEW CLEAN LAYOUT - Widget _buildProductCard(ProductAnalyticData product, int index) { + Widget _buildProductCard( + ProductAnalytic productAnalytic, + ProductAnalyticData product, + int index, + ) { return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: Duration(milliseconds: 600 + (index * 100)), @@ -344,9 +343,9 @@ class _ProductAnalyticPageState extends State opacity: clampedValue, child: Container( margin: EdgeInsets.only( - bottom: index == sampleData.data.length - 1 ? 0 : 16, + bottom: index == productAnalytic.data.length - 1 ? 0 : 16, ), - child: _buildCardContent(product, index), + child: _buildCardContent(productAnalytic, product, index), ), ), ); @@ -354,7 +353,11 @@ class _ProductAnalyticPageState extends State ); } - Widget _buildCardContent(ProductAnalyticData product, int index) { + Widget _buildCardContent( + ProductAnalytic productAnalytic, + ProductAnalyticData product, + int index, + ) { return Container( decoration: BoxDecoration( color: AppColor.white, @@ -383,7 +386,7 @@ class _ProductAnalyticPageState extends State child: Column( children: [ _buildCardHeader(product, index), - _buildCardBody(product), + _buildCardBody(productAnalytic, product), ], ), ), @@ -410,8 +413,11 @@ class _ProductAnalyticPageState extends State ); } - Widget _buildCardBody(ProductAnalyticData product) { - final index = sampleData.data.indexOf(product); + Widget _buildCardBody( + ProductAnalytic productAnalytic, + ProductAnalyticData product, + ) { + final index = productAnalytic.data.indexOf(product); return Padding( padding: const EdgeInsets.all(24), @@ -546,7 +552,7 @@ class _ProductAnalyticPageState extends State ), const SizedBox(height: 8), Text( - _formatCurrency(product.revenue), + _formatCurrency(product.revenue.toDouble()), style: _getTextStyle( AppStyle.xl, color: AppColor.success, diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index 91cc50f..939877e 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -321,7 +321,7 @@ class ProductAnalyticRoute extends _i20.PageRouteInfo { static _i20.PageInfo page = _i20.PageInfo( name, builder: (data) { - return const _i12.ProductAnalyticPage(); + return _i20.WrappedRoute(child: const _i12.ProductAnalyticPage()); }, ); }