Compare commits

..

No commits in common. "577adb7964bdc7f22c87ef130cd7dbdb8ad4d502" and "5387d7b7a6ae12eefed1f57bb11961b50ab419f2" have entirely different histories.

91 changed files with 1479 additions and 17910 deletions

View File

@ -1,51 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
part 'category_analytic_loader_event.dart';
part 'category_analytic_loader_state.dart';
part 'category_analytic_loader_bloc.freezed.dart';
@injectable
class CategoryAnalyticLoaderBloc
extends Bloc<CategoryAnalyticLoaderEvent, CategoryAnalyticLoaderState> {
final IAnalyticRepository _repository;
CategoryAnalyticLoaderBloc(this._repository)
: super(CategoryAnalyticLoaderState.initial()) {
on<CategoryAnalyticLoaderEvent>(_onCategoryAnalyticLoaderEvent);
}
Future<void> _onCategoryAnalyticLoaderEvent(
CategoryAnalyticLoaderEvent event,
Emitter<CategoryAnalyticLoaderState> emit,
) {
return event.map(
fetched: (e) async {
emit(
state.copyWith(
isFetching: true,
failureOptionCategoryAnalytic: none(),
),
);
final result = await _repository.getCategory(
dateFrom: DateTime.now().subtract(const Duration(days: 30)),
dateTo: DateTime.now(),
);
var data = result.fold(
(f) => state.copyWith(failureOptionCategoryAnalytic: optionOf(f)),
(categoryAnalytic) =>
state.copyWith(categoryAnalytic: categoryAnalytic),
);
emit(data.copyWith(isFetching: false));
},
);
}
}

View File

@ -1,401 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'category_analytic_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$CategoryAnalyticLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryAnalyticLoaderEventCopyWith<$Res> {
factory $CategoryAnalyticLoaderEventCopyWith(
CategoryAnalyticLoaderEvent value,
$Res Function(CategoryAnalyticLoaderEvent) then,
) =
_$CategoryAnalyticLoaderEventCopyWithImpl<
$Res,
CategoryAnalyticLoaderEvent
>;
}
/// @nodoc
class _$CategoryAnalyticLoaderEventCopyWithImpl<
$Res,
$Val extends CategoryAnalyticLoaderEvent
>
implements $CategoryAnalyticLoaderEventCopyWith<$Res> {
_$CategoryAnalyticLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$CategoryAnalyticLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl();
@override
String toString() {
return 'CategoryAnalyticLoaderEvent.fetched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({required TResult Function() fetched}) {
return fetched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched}) {
return fetched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements CategoryAnalyticLoaderEvent {
const factory _Fetched() = _$FetchedImpl;
}
/// @nodoc
mixin _$CategoryAnalyticLoaderState {
CategoryAnalytic get categoryAnalytic => throw _privateConstructorUsedError;
Option<AnalyticFailure> get failureOptionCategoryAnalytic =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of CategoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CategoryAnalyticLoaderStateCopyWith<CategoryAnalyticLoaderState>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryAnalyticLoaderStateCopyWith<$Res> {
factory $CategoryAnalyticLoaderStateCopyWith(
CategoryAnalyticLoaderState value,
$Res Function(CategoryAnalyticLoaderState) then,
) =
_$CategoryAnalyticLoaderStateCopyWithImpl<
$Res,
CategoryAnalyticLoaderState
>;
@useResult
$Res call({
CategoryAnalytic categoryAnalytic,
Option<AnalyticFailure> failureOptionCategoryAnalytic,
bool isFetching,
});
$CategoryAnalyticCopyWith<$Res> get categoryAnalytic;
}
/// @nodoc
class _$CategoryAnalyticLoaderStateCopyWithImpl<
$Res,
$Val extends CategoryAnalyticLoaderState
>
implements $CategoryAnalyticLoaderStateCopyWith<$Res> {
_$CategoryAnalyticLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? categoryAnalytic = null,
Object? failureOptionCategoryAnalytic = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
categoryAnalytic: null == categoryAnalytic
? _value.categoryAnalytic
: categoryAnalytic // ignore: cast_nullable_to_non_nullable
as CategoryAnalytic,
failureOptionCategoryAnalytic: null == failureOptionCategoryAnalytic
? _value.failureOptionCategoryAnalytic
: failureOptionCategoryAnalytic // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of CategoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CategoryAnalyticCopyWith<$Res> get categoryAnalytic {
return $CategoryAnalyticCopyWith<$Res>(_value.categoryAnalytic, (value) {
return _then(_value.copyWith(categoryAnalytic: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$CategoryAnalyticLoaderStateImplCopyWith<$Res>
implements $CategoryAnalyticLoaderStateCopyWith<$Res> {
factory _$$CategoryAnalyticLoaderStateImplCopyWith(
_$CategoryAnalyticLoaderStateImpl value,
$Res Function(_$CategoryAnalyticLoaderStateImpl) then,
) = __$$CategoryAnalyticLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
CategoryAnalytic categoryAnalytic,
Option<AnalyticFailure> failureOptionCategoryAnalytic,
bool isFetching,
});
@override
$CategoryAnalyticCopyWith<$Res> get categoryAnalytic;
}
/// @nodoc
class __$$CategoryAnalyticLoaderStateImplCopyWithImpl<$Res>
extends
_$CategoryAnalyticLoaderStateCopyWithImpl<
$Res,
_$CategoryAnalyticLoaderStateImpl
>
implements _$$CategoryAnalyticLoaderStateImplCopyWith<$Res> {
__$$CategoryAnalyticLoaderStateImplCopyWithImpl(
_$CategoryAnalyticLoaderStateImpl _value,
$Res Function(_$CategoryAnalyticLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? categoryAnalytic = null,
Object? failureOptionCategoryAnalytic = null,
Object? isFetching = null,
}) {
return _then(
_$CategoryAnalyticLoaderStateImpl(
categoryAnalytic: null == categoryAnalytic
? _value.categoryAnalytic
: categoryAnalytic // ignore: cast_nullable_to_non_nullable
as CategoryAnalytic,
failureOptionCategoryAnalytic: null == failureOptionCategoryAnalytic
? _value.failureOptionCategoryAnalytic
: failureOptionCategoryAnalytic // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$CategoryAnalyticLoaderStateImpl
implements _CategoryAnalyticLoaderState {
const _$CategoryAnalyticLoaderStateImpl({
required this.categoryAnalytic,
required this.failureOptionCategoryAnalytic,
this.isFetching = false,
});
@override
final CategoryAnalytic categoryAnalytic;
@override
final Option<AnalyticFailure> failureOptionCategoryAnalytic;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'CategoryAnalyticLoaderState(categoryAnalytic: $categoryAnalytic, failureOptionCategoryAnalytic: $failureOptionCategoryAnalytic, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CategoryAnalyticLoaderStateImpl &&
(identical(other.categoryAnalytic, categoryAnalytic) ||
other.categoryAnalytic == categoryAnalytic) &&
(identical(
other.failureOptionCategoryAnalytic,
failureOptionCategoryAnalytic,
) ||
other.failureOptionCategoryAnalytic ==
failureOptionCategoryAnalytic) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode => Object.hash(
runtimeType,
categoryAnalytic,
failureOptionCategoryAnalytic,
isFetching,
);
/// Create a copy of CategoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CategoryAnalyticLoaderStateImplCopyWith<_$CategoryAnalyticLoaderStateImpl>
get copyWith =>
__$$CategoryAnalyticLoaderStateImplCopyWithImpl<
_$CategoryAnalyticLoaderStateImpl
>(this, _$identity);
}
abstract class _CategoryAnalyticLoaderState
implements CategoryAnalyticLoaderState {
const factory _CategoryAnalyticLoaderState({
required final CategoryAnalytic categoryAnalytic,
required final Option<AnalyticFailure> failureOptionCategoryAnalytic,
final bool isFetching,
}) = _$CategoryAnalyticLoaderStateImpl;
@override
CategoryAnalytic get categoryAnalytic;
@override
Option<AnalyticFailure> get failureOptionCategoryAnalytic;
@override
bool get isFetching;
/// Create a copy of CategoryAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CategoryAnalyticLoaderStateImplCopyWith<_$CategoryAnalyticLoaderStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -1,6 +0,0 @@
part of 'category_analytic_loader_bloc.dart';
@freezed
class CategoryAnalyticLoaderEvent with _$CategoryAnalyticLoaderEvent {
const factory CategoryAnalyticLoaderEvent.fetched() = _Fetched;
}

View File

@ -1,15 +0,0 @@
part of 'category_analytic_loader_bloc.dart';
@freezed
class CategoryAnalyticLoaderState with _$CategoryAnalyticLoaderState {
const factory CategoryAnalyticLoaderState({
required CategoryAnalytic categoryAnalytic,
required Option<AnalyticFailure> failureOptionCategoryAnalytic,
@Default(false) bool isFetching,
}) = _CategoryAnalyticLoaderState;
factory CategoryAnalyticLoaderState.initial() => CategoryAnalyticLoaderState(
categoryAnalytic: CategoryAnalytic.empty(),
failureOptionCategoryAnalytic: none(),
);
}

View File

@ -1,44 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
part 'profit_loss_loader_event.dart';
part 'profit_loss_loader_state.dart';
part 'profit_loss_loader_bloc.freezed.dart';
@injectable
class ProfitLossLoaderBloc
extends Bloc<ProfitLossLoaderEvent, ProfitLossLoaderState> {
final IAnalyticRepository _repository;
ProfitLossLoaderBloc(this._repository)
: super(ProfitLossLoaderState.initial()) {
on<ProfitLossLoaderEvent>(_onProfitLossLoaderEvent);
}
Future<void> _onProfitLossLoaderEvent(
ProfitLossLoaderEvent event,
Emitter<ProfitLossLoaderState> emit,
) {
return event.map(
fetched: (e) async {
emit(state.copyWith(isFetching: true, failureOptionProfitLoss: none()));
final result = await _repository.getProfitLoss(
dateFrom: DateTime.now().subtract(const Duration(days: 30)),
dateTo: DateTime.now(),
);
var data = result.fold(
(f) => state.copyWith(failureOptionProfitLoss: optionOf(f)),
(profitLoss) => state.copyWith(profitLoss: profitLoss),
);
emit(data.copyWith(isFetching: false));
},
);
}
}

View File

@ -1,384 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'profit_loss_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$ProfitLossLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProfitLossLoaderEventCopyWith<$Res> {
factory $ProfitLossLoaderEventCopyWith(
ProfitLossLoaderEvent value,
$Res Function(ProfitLossLoaderEvent) then,
) = _$ProfitLossLoaderEventCopyWithImpl<$Res, ProfitLossLoaderEvent>;
}
/// @nodoc
class _$ProfitLossLoaderEventCopyWithImpl<
$Res,
$Val extends ProfitLossLoaderEvent
>
implements $ProfitLossLoaderEventCopyWith<$Res> {
_$ProfitLossLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProfitLossLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$ProfitLossLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of ProfitLossLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl();
@override
String toString() {
return 'ProfitLossLoaderEvent.fetched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({required TResult Function() fetched}) {
return fetched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched}) {
return fetched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements ProfitLossLoaderEvent {
const factory _Fetched() = _$FetchedImpl;
}
/// @nodoc
mixin _$ProfitLossLoaderState {
ProfitLossAnalytic get profitLoss => throw _privateConstructorUsedError;
Option<AnalyticFailure> get failureOptionProfitLoss =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of ProfitLossLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ProfitLossLoaderStateCopyWith<ProfitLossLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProfitLossLoaderStateCopyWith<$Res> {
factory $ProfitLossLoaderStateCopyWith(
ProfitLossLoaderState value,
$Res Function(ProfitLossLoaderState) then,
) = _$ProfitLossLoaderStateCopyWithImpl<$Res, ProfitLossLoaderState>;
@useResult
$Res call({
ProfitLossAnalytic profitLoss,
Option<AnalyticFailure> failureOptionProfitLoss,
bool isFetching,
});
$ProfitLossAnalyticCopyWith<$Res> get profitLoss;
}
/// @nodoc
class _$ProfitLossLoaderStateCopyWithImpl<
$Res,
$Val extends ProfitLossLoaderState
>
implements $ProfitLossLoaderStateCopyWith<$Res> {
_$ProfitLossLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProfitLossLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? profitLoss = null,
Object? failureOptionProfitLoss = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
profitLoss: null == profitLoss
? _value.profitLoss
: profitLoss // ignore: cast_nullable_to_non_nullable
as ProfitLossAnalytic,
failureOptionProfitLoss: null == failureOptionProfitLoss
? _value.failureOptionProfitLoss
: failureOptionProfitLoss // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of ProfitLossLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$ProfitLossAnalyticCopyWith<$Res> get profitLoss {
return $ProfitLossAnalyticCopyWith<$Res>(_value.profitLoss, (value) {
return _then(_value.copyWith(profitLoss: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$ProfitLossLoaderStateImplCopyWith<$Res>
implements $ProfitLossLoaderStateCopyWith<$Res> {
factory _$$ProfitLossLoaderStateImplCopyWith(
_$ProfitLossLoaderStateImpl value,
$Res Function(_$ProfitLossLoaderStateImpl) then,
) = __$$ProfitLossLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
ProfitLossAnalytic profitLoss,
Option<AnalyticFailure> failureOptionProfitLoss,
bool isFetching,
});
@override
$ProfitLossAnalyticCopyWith<$Res> get profitLoss;
}
/// @nodoc
class __$$ProfitLossLoaderStateImplCopyWithImpl<$Res>
extends
_$ProfitLossLoaderStateCopyWithImpl<$Res, _$ProfitLossLoaderStateImpl>
implements _$$ProfitLossLoaderStateImplCopyWith<$Res> {
__$$ProfitLossLoaderStateImplCopyWithImpl(
_$ProfitLossLoaderStateImpl _value,
$Res Function(_$ProfitLossLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of ProfitLossLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? profitLoss = null,
Object? failureOptionProfitLoss = null,
Object? isFetching = null,
}) {
return _then(
_$ProfitLossLoaderStateImpl(
profitLoss: null == profitLoss
? _value.profitLoss
: profitLoss // ignore: cast_nullable_to_non_nullable
as ProfitLossAnalytic,
failureOptionProfitLoss: null == failureOptionProfitLoss
? _value.failureOptionProfitLoss
: failureOptionProfitLoss // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$ProfitLossLoaderStateImpl implements _ProfitLossLoaderState {
const _$ProfitLossLoaderStateImpl({
required this.profitLoss,
required this.failureOptionProfitLoss,
this.isFetching = false,
});
@override
final ProfitLossAnalytic profitLoss;
@override
final Option<AnalyticFailure> failureOptionProfitLoss;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'ProfitLossLoaderState(profitLoss: $profitLoss, failureOptionProfitLoss: $failureOptionProfitLoss, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProfitLossLoaderStateImpl &&
(identical(other.profitLoss, profitLoss) ||
other.profitLoss == profitLoss) &&
(identical(
other.failureOptionProfitLoss,
failureOptionProfitLoss,
) ||
other.failureOptionProfitLoss == failureOptionProfitLoss) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode =>
Object.hash(runtimeType, profitLoss, failureOptionProfitLoss, isFetching);
/// Create a copy of ProfitLossLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ProfitLossLoaderStateImplCopyWith<_$ProfitLossLoaderStateImpl>
get copyWith =>
__$$ProfitLossLoaderStateImplCopyWithImpl<_$ProfitLossLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _ProfitLossLoaderState implements ProfitLossLoaderState {
const factory _ProfitLossLoaderState({
required final ProfitLossAnalytic profitLoss,
required final Option<AnalyticFailure> failureOptionProfitLoss,
final bool isFetching,
}) = _$ProfitLossLoaderStateImpl;
@override
ProfitLossAnalytic get profitLoss;
@override
Option<AnalyticFailure> get failureOptionProfitLoss;
@override
bool get isFetching;
/// Create a copy of ProfitLossLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ProfitLossLoaderStateImplCopyWith<_$ProfitLossLoaderStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -1,6 +0,0 @@
part of 'profit_loss_loader_bloc.dart';
@freezed
class ProfitLossLoaderEvent with _$ProfitLossLoaderEvent {
const factory ProfitLossLoaderEvent.fetched() = _Fetched;
}

View File

@ -1,15 +0,0 @@
part of 'profit_loss_loader_bloc.dart';
@freezed
class ProfitLossLoaderState with _$ProfitLossLoaderState {
const factory ProfitLossLoaderState({
required ProfitLossAnalytic profitLoss,
required Option<AnalyticFailure> failureOptionProfitLoss,
@Default(false) bool isFetching,
}) = _ProfitLossLoaderState;
factory ProfitLossLoaderState.initial() => ProfitLossLoaderState(
profitLoss: ProfitLossAnalytic.empty(),
failureOptionProfitLoss: none(),
);
}

View File

@ -1,39 +0,0 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
part 'sales_loader_event.dart';
part 'sales_loader_state.dart';
part 'sales_loader_bloc.freezed.dart';
@injectable
class SalesLoaderBloc extends Bloc<SalesLoaderEvent, SalesLoaderState> {
final IAnalyticRepository _analyticRepository;
SalesLoaderBloc(this._analyticRepository)
: super(SalesLoaderState.initial()) {
on<SalesLoaderEvent>(_onSalesLoaderEvent);
}
Future<void> _onSalesLoaderEvent(
SalesLoaderEvent event,
Emitter<SalesLoaderState> emit,
) async {
emit(state.copyWith(isFetching: true, failureOptionSales: none()));
final result = await _analyticRepository.getSales(
dateFrom: DateTime.now().subtract(const Duration(days: 30)),
dateTo: DateTime.now(),
);
var data = result.fold(
(f) => state.copyWith(failureOptionSales: optionOf(f)),
(sales) => state.copyWith(sales: sales),
);
emit(data.copyWith(isFetching: false));
}
}

View File

@ -1,376 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'sales_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$SalesLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fectched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fectched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fectched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fectched value) fectched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fectched value)? fectched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fectched value)? fectched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SalesLoaderEventCopyWith<$Res> {
factory $SalesLoaderEventCopyWith(
SalesLoaderEvent value,
$Res Function(SalesLoaderEvent) then,
) = _$SalesLoaderEventCopyWithImpl<$Res, SalesLoaderEvent>;
}
/// @nodoc
class _$SalesLoaderEventCopyWithImpl<$Res, $Val extends SalesLoaderEvent>
implements $SalesLoaderEventCopyWith<$Res> {
_$SalesLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of SalesLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FectchedImplCopyWith<$Res> {
factory _$$FectchedImplCopyWith(
_$FectchedImpl value,
$Res Function(_$FectchedImpl) then,
) = __$$FectchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FectchedImplCopyWithImpl<$Res>
extends _$SalesLoaderEventCopyWithImpl<$Res, _$FectchedImpl>
implements _$$FectchedImplCopyWith<$Res> {
__$$FectchedImplCopyWithImpl(
_$FectchedImpl _value,
$Res Function(_$FectchedImpl) _then,
) : super(_value, _then);
/// Create a copy of SalesLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FectchedImpl implements _Fectched {
const _$FectchedImpl();
@override
String toString() {
return 'SalesLoaderEvent.fectched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FectchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fectched,
}) {
return fectched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fectched,
}) {
return fectched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fectched,
required TResult orElse(),
}) {
if (fectched != null) {
return fectched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fectched value) fectched,
}) {
return fectched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fectched value)? fectched,
}) {
return fectched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fectched value)? fectched,
required TResult orElse(),
}) {
if (fectched != null) {
return fectched(this);
}
return orElse();
}
}
abstract class _Fectched implements SalesLoaderEvent {
const factory _Fectched() = _$FectchedImpl;
}
/// @nodoc
mixin _$SalesLoaderState {
SalesAnalytic get sales => throw _privateConstructorUsedError;
Option<AnalyticFailure> get failureOptionSales =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of SalesLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$SalesLoaderStateCopyWith<SalesLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SalesLoaderStateCopyWith<$Res> {
factory $SalesLoaderStateCopyWith(
SalesLoaderState value,
$Res Function(SalesLoaderState) then,
) = _$SalesLoaderStateCopyWithImpl<$Res, SalesLoaderState>;
@useResult
$Res call({
SalesAnalytic sales,
Option<AnalyticFailure> failureOptionSales,
bool isFetching,
});
$SalesAnalyticCopyWith<$Res> get sales;
}
/// @nodoc
class _$SalesLoaderStateCopyWithImpl<$Res, $Val extends SalesLoaderState>
implements $SalesLoaderStateCopyWith<$Res> {
_$SalesLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of SalesLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? sales = null,
Object? failureOptionSales = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
sales: null == sales
? _value.sales
: sales // ignore: cast_nullable_to_non_nullable
as SalesAnalytic,
failureOptionSales: null == failureOptionSales
? _value.failureOptionSales
: failureOptionSales // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of SalesLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SalesAnalyticCopyWith<$Res> get sales {
return $SalesAnalyticCopyWith<$Res>(_value.sales, (value) {
return _then(_value.copyWith(sales: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$SalesLoaderStateImplCopyWith<$Res>
implements $SalesLoaderStateCopyWith<$Res> {
factory _$$SalesLoaderStateImplCopyWith(
_$SalesLoaderStateImpl value,
$Res Function(_$SalesLoaderStateImpl) then,
) = __$$SalesLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
SalesAnalytic sales,
Option<AnalyticFailure> failureOptionSales,
bool isFetching,
});
@override
$SalesAnalyticCopyWith<$Res> get sales;
}
/// @nodoc
class __$$SalesLoaderStateImplCopyWithImpl<$Res>
extends _$SalesLoaderStateCopyWithImpl<$Res, _$SalesLoaderStateImpl>
implements _$$SalesLoaderStateImplCopyWith<$Res> {
__$$SalesLoaderStateImplCopyWithImpl(
_$SalesLoaderStateImpl _value,
$Res Function(_$SalesLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of SalesLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? sales = null,
Object? failureOptionSales = null,
Object? isFetching = null,
}) {
return _then(
_$SalesLoaderStateImpl(
sales: null == sales
? _value.sales
: sales // ignore: cast_nullable_to_non_nullable
as SalesAnalytic,
failureOptionSales: null == failureOptionSales
? _value.failureOptionSales
: failureOptionSales // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$SalesLoaderStateImpl implements _SalesLoaderState {
const _$SalesLoaderStateImpl({
required this.sales,
required this.failureOptionSales,
this.isFetching = false,
});
@override
final SalesAnalytic sales;
@override
final Option<AnalyticFailure> failureOptionSales;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'SalesLoaderState(sales: $sales, failureOptionSales: $failureOptionSales, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SalesLoaderStateImpl &&
(identical(other.sales, sales) || other.sales == sales) &&
(identical(other.failureOptionSales, failureOptionSales) ||
other.failureOptionSales == failureOptionSales) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode =>
Object.hash(runtimeType, sales, failureOptionSales, isFetching);
/// Create a copy of SalesLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SalesLoaderStateImplCopyWith<_$SalesLoaderStateImpl> get copyWith =>
__$$SalesLoaderStateImplCopyWithImpl<_$SalesLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _SalesLoaderState implements SalesLoaderState {
const factory _SalesLoaderState({
required final SalesAnalytic sales,
required final Option<AnalyticFailure> failureOptionSales,
final bool isFetching,
}) = _$SalesLoaderStateImpl;
@override
SalesAnalytic get sales;
@override
Option<AnalyticFailure> get failureOptionSales;
@override
bool get isFetching;
/// Create a copy of SalesLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SalesLoaderStateImplCopyWith<_$SalesLoaderStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,6 +0,0 @@
part of 'sales_loader_bloc.dart';
@freezed
class SalesLoaderEvent with _$SalesLoaderEvent {
const factory SalesLoaderEvent.fectched() = _Fectched;
}

View File

@ -1,15 +0,0 @@
part of 'sales_loader_bloc.dart';
@freezed
class SalesLoaderState with _$SalesLoaderState {
const factory SalesLoaderState({
required SalesAnalytic sales,
required Option<AnalyticFailure> failureOptionSales,
@Default(false) bool isFetching,
}) = _SalesLoaderState;
factory SalesLoaderState.initial() => SalesLoaderState(
sales: SalesAnalytic.empty(),
failureOptionSales: none(),
);
}

View File

@ -1,55 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/category/category.dart';
part 'category_loader_event.dart';
part 'category_loader_state.dart';
part 'category_loader_bloc.freezed.dart';
@injectable
class CategoryLoaderBloc
extends Bloc<CategoryLoaderEvent, CategoryLoaderState> {
final ICategoryRepository _repository;
CategoryLoaderBloc(this._repository) : super(CategoryLoaderState.initial()) {
on<CategoryLoaderEvent>(_onCategoryLoaderEvent);
}
Future<void> _onCategoryLoaderEvent(
CategoryLoaderEvent event,
Emitter<CategoryLoaderState> emit,
) {
return event.map(
fetched: (e) async {
emit(state.copyWith(isFetching: true, failureOptionCategory: none()));
final result = await _repository.get();
result.fold(
(f) {
emit(
state.copyWith(
isFetching: false,
failureOptionCategory: optionOf(f),
),
);
},
(categories) {
// tambahkan "All Data" di awal list
final updatedCategories = [Category.addAllData(), ...categories];
emit(
state.copyWith(
isFetching: false,
categories: updatedCategories,
failureOptionCategory: none(),
),
);
},
);
},
);
}
}

View File

@ -1,370 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'category_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$CategoryLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryLoaderEventCopyWith<$Res> {
factory $CategoryLoaderEventCopyWith(
CategoryLoaderEvent value,
$Res Function(CategoryLoaderEvent) then,
) = _$CategoryLoaderEventCopyWithImpl<$Res, CategoryLoaderEvent>;
}
/// @nodoc
class _$CategoryLoaderEventCopyWithImpl<$Res, $Val extends CategoryLoaderEvent>
implements $CategoryLoaderEventCopyWith<$Res> {
_$CategoryLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$CategoryLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl();
@override
String toString() {
return 'CategoryLoaderEvent.fetched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({required TResult Function() fetched}) {
return fetched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched}) {
return fetched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements CategoryLoaderEvent {
const factory _Fetched() = _$FetchedImpl;
}
/// @nodoc
mixin _$CategoryLoaderState {
List<Category> get categories => throw _privateConstructorUsedError;
Option<CategoryFailure> get failureOptionCategory =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of CategoryLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CategoryLoaderStateCopyWith<CategoryLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryLoaderStateCopyWith<$Res> {
factory $CategoryLoaderStateCopyWith(
CategoryLoaderState value,
$Res Function(CategoryLoaderState) then,
) = _$CategoryLoaderStateCopyWithImpl<$Res, CategoryLoaderState>;
@useResult
$Res call({
List<Category> categories,
Option<CategoryFailure> failureOptionCategory,
bool isFetching,
});
}
/// @nodoc
class _$CategoryLoaderStateCopyWithImpl<$Res, $Val extends CategoryLoaderState>
implements $CategoryLoaderStateCopyWith<$Res> {
_$CategoryLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? categories = null,
Object? failureOptionCategory = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
categories: null == categories
? _value.categories
: categories // ignore: cast_nullable_to_non_nullable
as List<Category>,
failureOptionCategory: null == failureOptionCategory
? _value.failureOptionCategory
: failureOptionCategory // ignore: cast_nullable_to_non_nullable
as Option<CategoryFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$CategoryLoaderStateImplCopyWith<$Res>
implements $CategoryLoaderStateCopyWith<$Res> {
factory _$$CategoryLoaderStateImplCopyWith(
_$CategoryLoaderStateImpl value,
$Res Function(_$CategoryLoaderStateImpl) then,
) = __$$CategoryLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
List<Category> categories,
Option<CategoryFailure> failureOptionCategory,
bool isFetching,
});
}
/// @nodoc
class __$$CategoryLoaderStateImplCopyWithImpl<$Res>
extends _$CategoryLoaderStateCopyWithImpl<$Res, _$CategoryLoaderStateImpl>
implements _$$CategoryLoaderStateImplCopyWith<$Res> {
__$$CategoryLoaderStateImplCopyWithImpl(
_$CategoryLoaderStateImpl _value,
$Res Function(_$CategoryLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? categories = null,
Object? failureOptionCategory = null,
Object? isFetching = null,
}) {
return _then(
_$CategoryLoaderStateImpl(
categories: null == categories
? _value._categories
: categories // ignore: cast_nullable_to_non_nullable
as List<Category>,
failureOptionCategory: null == failureOptionCategory
? _value.failureOptionCategory
: failureOptionCategory // ignore: cast_nullable_to_non_nullable
as Option<CategoryFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$CategoryLoaderStateImpl implements _CategoryLoaderState {
const _$CategoryLoaderStateImpl({
required final List<Category> categories,
required this.failureOptionCategory,
this.isFetching = false,
}) : _categories = categories;
final List<Category> _categories;
@override
List<Category> get categories {
if (_categories is EqualUnmodifiableListView) return _categories;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_categories);
}
@override
final Option<CategoryFailure> failureOptionCategory;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'CategoryLoaderState(categories: $categories, failureOptionCategory: $failureOptionCategory, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CategoryLoaderStateImpl &&
const DeepCollectionEquality().equals(
other._categories,
_categories,
) &&
(identical(other.failureOptionCategory, failureOptionCategory) ||
other.failureOptionCategory == failureOptionCategory) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(_categories),
failureOptionCategory,
isFetching,
);
/// Create a copy of CategoryLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CategoryLoaderStateImplCopyWith<_$CategoryLoaderStateImpl> get copyWith =>
__$$CategoryLoaderStateImplCopyWithImpl<_$CategoryLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _CategoryLoaderState implements CategoryLoaderState {
const factory _CategoryLoaderState({
required final List<Category> categories,
required final Option<CategoryFailure> failureOptionCategory,
final bool isFetching,
}) = _$CategoryLoaderStateImpl;
@override
List<Category> get categories;
@override
Option<CategoryFailure> get failureOptionCategory;
@override
bool get isFetching;
/// Create a copy of CategoryLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CategoryLoaderStateImplCopyWith<_$CategoryLoaderStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,6 +0,0 @@
part of 'category_loader_bloc.dart';
@freezed
class CategoryLoaderEvent with _$CategoryLoaderEvent {
const factory CategoryLoaderEvent.fetched() = _Fetched;
}

View File

@ -1,13 +0,0 @@
part of 'category_loader_bloc.dart';
@freezed
class CategoryLoaderState with _$CategoryLoaderState {
const factory CategoryLoaderState({
required List<Category> categories,
required Option<CategoryFailure> failureOptionCategory,
@Default(false) bool isFetching,
}) = _CategoryLoaderState;
factory CategoryLoaderState.initial() =>
CategoryLoaderState(categories: [], failureOptionCategory: none());
}

View File

@ -1,92 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/product/product.dart';
part 'product_loader_event.dart';
part 'product_loader_state.dart';
part 'product_loader_bloc.freezed.dart';
@injectable
class ProductLoaderBloc extends Bloc<ProductLoaderEvent, ProductLoaderState> {
final IProductRepository _productRepository;
ProductLoaderBloc(this._productRepository)
: super(ProductLoaderState.initial()) {
on<ProductLoaderEvent>(_onProductLoaderEvent);
}
Future<void> _onProductLoaderEvent(
ProductLoaderEvent event,
Emitter<ProductLoaderState> emit,
) {
return event.map(
categoryIdChanged: (e) async {
emit(state.copyWith(categoryId: e.categoryId));
},
searchChanged: (e) async {
emit(state.copyWith(search: e.search));
},
fetched: (e) async {
var newState = state;
if (e.isRefresh) {
newState = state.copyWith(isFetching: true);
emit(newState);
}
newState = await _mapFetchedToState(state, isRefresh: e.isRefresh);
emit(newState);
},
);
}
Future<ProductLoaderState> _mapFetchedToState(
ProductLoaderState state, {
bool isRefresh = false,
}) async {
state = state.copyWith(isFetching: false);
if (state.hasReachedMax && state.products.isNotEmpty && !isRefresh) {
return state;
}
if (isRefresh) {
state = state.copyWith(
page: 1,
failureOptionProduct: none(),
hasReachedMax: false,
products: [],
);
}
final failureOrProduct = await _productRepository.get(
categoryId: state.categoryId,
page: state.page,
search: state.search,
);
state = failureOrProduct.fold(
(f) {
if (state.products.isNotEmpty) {
return state.copyWith(hasReachedMax: true);
}
return state.copyWith(failureOptionProduct: optionOf(f));
},
(products) {
return state.copyWith(
products: List.from(state.products)..addAll(products),
failureOptionProduct: none(),
page: state.page + 1,
hasReachedMax: products.length < 10,
);
},
);
return state;
}
}

View File

@ -1,821 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'product_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$ProductLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String categoryId) categoryIdChanged,
required TResult Function(String search) searchChanged,
required TResult Function(bool isRefresh) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String categoryId)? categoryIdChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String categoryId)? categoryIdChanged,
TResult Function(String search)? searchChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_CategoryIdChanged value) categoryIdChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_CategoryIdChanged value)? categoryIdChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_CategoryIdChanged value)? categoryIdChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProductLoaderEventCopyWith<$Res> {
factory $ProductLoaderEventCopyWith(
ProductLoaderEvent value,
$Res Function(ProductLoaderEvent) then,
) = _$ProductLoaderEventCopyWithImpl<$Res, ProductLoaderEvent>;
}
/// @nodoc
class _$ProductLoaderEventCopyWithImpl<$Res, $Val extends ProductLoaderEvent>
implements $ProductLoaderEventCopyWith<$Res> {
_$ProductLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$CategoryIdChangedImplCopyWith<$Res> {
factory _$$CategoryIdChangedImplCopyWith(
_$CategoryIdChangedImpl value,
$Res Function(_$CategoryIdChangedImpl) then,
) = __$$CategoryIdChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({String categoryId});
}
/// @nodoc
class __$$CategoryIdChangedImplCopyWithImpl<$Res>
extends _$ProductLoaderEventCopyWithImpl<$Res, _$CategoryIdChangedImpl>
implements _$$CategoryIdChangedImplCopyWith<$Res> {
__$$CategoryIdChangedImplCopyWithImpl(
_$CategoryIdChangedImpl _value,
$Res Function(_$CategoryIdChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? categoryId = null}) {
return _then(
_$CategoryIdChangedImpl(
null == categoryId
? _value.categoryId
: categoryId // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$CategoryIdChangedImpl implements _CategoryIdChanged {
const _$CategoryIdChangedImpl(this.categoryId);
@override
final String categoryId;
@override
String toString() {
return 'ProductLoaderEvent.categoryIdChanged(categoryId: $categoryId)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CategoryIdChangedImpl &&
(identical(other.categoryId, categoryId) ||
other.categoryId == categoryId));
}
@override
int get hashCode => Object.hash(runtimeType, categoryId);
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CategoryIdChangedImplCopyWith<_$CategoryIdChangedImpl> get copyWith =>
__$$CategoryIdChangedImplCopyWithImpl<_$CategoryIdChangedImpl>(
this,
_$identity,
);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String categoryId) categoryIdChanged,
required TResult Function(String search) searchChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return categoryIdChanged(categoryId);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String categoryId)? categoryIdChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return categoryIdChanged?.call(categoryId);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String categoryId)? categoryIdChanged,
TResult Function(String search)? searchChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (categoryIdChanged != null) {
return categoryIdChanged(categoryId);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_CategoryIdChanged value) categoryIdChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) {
return categoryIdChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_CategoryIdChanged value)? categoryIdChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return categoryIdChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_CategoryIdChanged value)? categoryIdChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (categoryIdChanged != null) {
return categoryIdChanged(this);
}
return orElse();
}
}
abstract class _CategoryIdChanged implements ProductLoaderEvent {
const factory _CategoryIdChanged(final String categoryId) =
_$CategoryIdChangedImpl;
String get categoryId;
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CategoryIdChangedImplCopyWith<_$CategoryIdChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$SearchChangedImplCopyWith<$Res> {
factory _$$SearchChangedImplCopyWith(
_$SearchChangedImpl value,
$Res Function(_$SearchChangedImpl) then,
) = __$$SearchChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({String search});
}
/// @nodoc
class __$$SearchChangedImplCopyWithImpl<$Res>
extends _$ProductLoaderEventCopyWithImpl<$Res, _$SearchChangedImpl>
implements _$$SearchChangedImplCopyWith<$Res> {
__$$SearchChangedImplCopyWithImpl(
_$SearchChangedImpl _value,
$Res Function(_$SearchChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? search = null}) {
return _then(
_$SearchChangedImpl(
null == search
? _value.search
: search // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$SearchChangedImpl implements _SearchChanged {
const _$SearchChangedImpl(this.search);
@override
final String search;
@override
String toString() {
return 'ProductLoaderEvent.searchChanged(search: $search)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SearchChangedImpl &&
(identical(other.search, search) || other.search == search));
}
@override
int get hashCode => Object.hash(runtimeType, search);
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SearchChangedImplCopyWith<_$SearchChangedImpl> get copyWith =>
__$$SearchChangedImplCopyWithImpl<_$SearchChangedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String categoryId) categoryIdChanged,
required TResult Function(String search) searchChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return searchChanged(search);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String categoryId)? categoryIdChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return searchChanged?.call(search);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String categoryId)? categoryIdChanged,
TResult Function(String search)? searchChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (searchChanged != null) {
return searchChanged(search);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_CategoryIdChanged value) categoryIdChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) {
return searchChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_CategoryIdChanged value)? categoryIdChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return searchChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_CategoryIdChanged value)? categoryIdChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (searchChanged != null) {
return searchChanged(this);
}
return orElse();
}
}
abstract class _SearchChanged implements ProductLoaderEvent {
const factory _SearchChanged(final String search) = _$SearchChangedImpl;
String get search;
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SearchChangedImplCopyWith<_$SearchChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
@useResult
$Res call({bool isRefresh});
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$ProductLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? isRefresh = null}) {
return _then(
_$FetchedImpl(
isRefresh: null == isRefresh
? _value.isRefresh
: isRefresh // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl({this.isRefresh = false});
@override
@JsonKey()
final bool isRefresh;
@override
String toString() {
return 'ProductLoaderEvent.fetched(isRefresh: $isRefresh)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$FetchedImpl &&
(identical(other.isRefresh, isRefresh) ||
other.isRefresh == isRefresh));
}
@override
int get hashCode => Object.hash(runtimeType, isRefresh);
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
__$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String categoryId) categoryIdChanged,
required TResult Function(String search) searchChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return fetched(isRefresh);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String categoryId)? categoryIdChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return fetched?.call(isRefresh);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String categoryId)? categoryIdChanged,
TResult Function(String search)? searchChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(isRefresh);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_CategoryIdChanged value) categoryIdChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_CategoryIdChanged value)? categoryIdChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_CategoryIdChanged value)? categoryIdChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements ProductLoaderEvent {
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
bool get isRefresh;
/// Create a copy of ProductLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ProductLoaderState {
List<Product> get products => throw _privateConstructorUsedError;
Option<ProductFailure> get failureOptionProduct =>
throw _privateConstructorUsedError;
String? get categoryId => throw _privateConstructorUsedError;
String? get search => throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
bool get hasReachedMax => throw _privateConstructorUsedError;
int get page => throw _privateConstructorUsedError;
/// Create a copy of ProductLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ProductLoaderStateCopyWith<ProductLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProductLoaderStateCopyWith<$Res> {
factory $ProductLoaderStateCopyWith(
ProductLoaderState value,
$Res Function(ProductLoaderState) then,
) = _$ProductLoaderStateCopyWithImpl<$Res, ProductLoaderState>;
@useResult
$Res call({
List<Product> products,
Option<ProductFailure> failureOptionProduct,
String? categoryId,
String? search,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class _$ProductLoaderStateCopyWithImpl<$Res, $Val extends ProductLoaderState>
implements $ProductLoaderStateCopyWith<$Res> {
_$ProductLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProductLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? products = null,
Object? failureOptionProduct = null,
Object? categoryId = freezed,
Object? search = freezed,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_value.copyWith(
products: null == products
? _value.products
: products // ignore: cast_nullable_to_non_nullable
as List<Product>,
failureOptionProduct: null == failureOptionProduct
? _value.failureOptionProduct
: failureOptionProduct // ignore: cast_nullable_to_non_nullable
as Option<ProductFailure>,
categoryId: freezed == categoryId
? _value.categoryId
: categoryId // ignore: cast_nullable_to_non_nullable
as String?,
search: freezed == search
? _value.search
: search // ignore: cast_nullable_to_non_nullable
as String?,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
hasReachedMax: null == hasReachedMax
? _value.hasReachedMax
: hasReachedMax // ignore: cast_nullable_to_non_nullable
as bool,
page: null == page
? _value.page
: page // ignore: cast_nullable_to_non_nullable
as int,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$ProductLoaderStateImplCopyWith<$Res>
implements $ProductLoaderStateCopyWith<$Res> {
factory _$$ProductLoaderStateImplCopyWith(
_$ProductLoaderStateImpl value,
$Res Function(_$ProductLoaderStateImpl) then,
) = __$$ProductLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
List<Product> products,
Option<ProductFailure> failureOptionProduct,
String? categoryId,
String? search,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class __$$ProductLoaderStateImplCopyWithImpl<$Res>
extends _$ProductLoaderStateCopyWithImpl<$Res, _$ProductLoaderStateImpl>
implements _$$ProductLoaderStateImplCopyWith<$Res> {
__$$ProductLoaderStateImplCopyWithImpl(
_$ProductLoaderStateImpl _value,
$Res Function(_$ProductLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of ProductLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? products = null,
Object? failureOptionProduct = null,
Object? categoryId = freezed,
Object? search = freezed,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_$ProductLoaderStateImpl(
products: null == products
? _value._products
: products // ignore: cast_nullable_to_non_nullable
as List<Product>,
failureOptionProduct: null == failureOptionProduct
? _value.failureOptionProduct
: failureOptionProduct // ignore: cast_nullable_to_non_nullable
as Option<ProductFailure>,
categoryId: freezed == categoryId
? _value.categoryId
: categoryId // ignore: cast_nullable_to_non_nullable
as String?,
search: freezed == search
? _value.search
: search // ignore: cast_nullable_to_non_nullable
as String?,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
hasReachedMax: null == hasReachedMax
? _value.hasReachedMax
: hasReachedMax // ignore: cast_nullable_to_non_nullable
as bool,
page: null == page
? _value.page
: page // ignore: cast_nullable_to_non_nullable
as int,
),
);
}
}
/// @nodoc
class _$ProductLoaderStateImpl implements _ProductLoaderState {
const _$ProductLoaderStateImpl({
required final List<Product> products,
required this.failureOptionProduct,
this.categoryId,
this.search,
this.isFetching = false,
this.hasReachedMax = false,
this.page = 1,
}) : _products = products;
final List<Product> _products;
@override
List<Product> get products {
if (_products is EqualUnmodifiableListView) return _products;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_products);
}
@override
final Option<ProductFailure> failureOptionProduct;
@override
final String? categoryId;
@override
final String? search;
@override
@JsonKey()
final bool isFetching;
@override
@JsonKey()
final bool hasReachedMax;
@override
@JsonKey()
final int page;
@override
String toString() {
return 'ProductLoaderState(products: $products, failureOptionProduct: $failureOptionProduct, categoryId: $categoryId, search: $search, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProductLoaderStateImpl &&
const DeepCollectionEquality().equals(other._products, _products) &&
(identical(other.failureOptionProduct, failureOptionProduct) ||
other.failureOptionProduct == failureOptionProduct) &&
(identical(other.categoryId, categoryId) ||
other.categoryId == categoryId) &&
(identical(other.search, search) || other.search == search) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching) &&
(identical(other.hasReachedMax, hasReachedMax) ||
other.hasReachedMax == hasReachedMax) &&
(identical(other.page, page) || other.page == page));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(_products),
failureOptionProduct,
categoryId,
search,
isFetching,
hasReachedMax,
page,
);
/// Create a copy of ProductLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ProductLoaderStateImplCopyWith<_$ProductLoaderStateImpl> get copyWith =>
__$$ProductLoaderStateImplCopyWithImpl<_$ProductLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _ProductLoaderState implements ProductLoaderState {
const factory _ProductLoaderState({
required final List<Product> products,
required final Option<ProductFailure> failureOptionProduct,
final String? categoryId,
final String? search,
final bool isFetching,
final bool hasReachedMax,
final int page,
}) = _$ProductLoaderStateImpl;
@override
List<Product> get products;
@override
Option<ProductFailure> get failureOptionProduct;
@override
String? get categoryId;
@override
String? get search;
@override
bool get isFetching;
@override
bool get hasReachedMax;
@override
int get page;
/// Create a copy of ProductLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ProductLoaderStateImplCopyWith<_$ProductLoaderStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,11 +0,0 @@
part of 'product_loader_bloc.dart';
@freezed
class ProductLoaderEvent with _$ProductLoaderEvent {
const factory ProductLoaderEvent.categoryIdChanged(String categoryId) =
_CategoryIdChanged;
const factory ProductLoaderEvent.searchChanged(String search) =
_SearchChanged;
const factory ProductLoaderEvent.fetched({@Default(false) bool isRefresh}) =
_Fetched;
}

View File

@ -1,17 +0,0 @@
part of 'product_loader_bloc.dart';
@freezed
class ProductLoaderState with _$ProductLoaderState {
const factory ProductLoaderState({
required List<Product> products,
required Option<ProductFailure> failureOptionProduct,
String? categoryId,
String? search,
@Default(false) bool isFetching,
@Default(false) bool hasReachedMax,
@Default(1) int page,
}) = _ProductLoaderState;
factory ProductLoaderState.initial() =>
ProductLoaderState(products: [], failureOptionProduct: none());
}

View File

@ -2,8 +2,10 @@ import 'package:awesome_dio_interceptor/awesome_dio_interceptor.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../env.dart';
import '../constant/local_storage_key.dart';
import 'api_failure.dart';
import 'errors/bad_network_error.dart';
import 'errors/bad_request_error.dart';
@ -22,11 +24,16 @@ import 'interceptors/unauthorized_interceptor.dart';
class ApiClient {
final Dio _dio;
final Env _env;
final SharedPreferences _preferences;
ApiClient(this._dio, this._env) {
ApiClient(this._dio, this._env, this._preferences) {
_dio.options.baseUrl = _env.baseUrl;
_dio.options.validateStatus = (status) => status! < 500;
_dio.options.connectTimeout = const Duration(seconds: 20);
_dio.options.headers = {
'authorization':
'Bearer ${_preferences.getString(LocalStorageKey.token)}',
};
_dio.interceptors.add(BadNetworkErrorInterceptor());
_dio.interceptors.add(BadRequestErrorInterceptor());
_dio.interceptors.add(InternalServerErrorInterceptor());

View File

@ -1,8 +1,4 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../injection.dart';
import '../constant/local_storage_key.dart';
void dismissKeyboard(BuildContext context) {
final currentFocus = FocusScope.of(context);
@ -10,10 +6,3 @@ void dismissKeyboard(BuildContext context) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
Map<String, dynamic> getAuthorizationHeader() {
return {
'Authorization':
'Bearer ${getIt<SharedPreferences>().getString(LocalStorageKey.token)}',
};
}

View File

@ -2,15 +2,4 @@ class ApiPath {
// Auth
static const String login = '/api/v1/auth/login';
static const String logout = '/api/v1/auth/logout';
// Analytic
static const String salesAnalytic = '/api/v1/analytics/sales';
static const String profitLossAnalytic = '/api/v1/analytics/profit-loss';
static const String categoryAnalytic = '/api/v1/analytics/categories';
// Category
static const String category = '/api/v1/categories';
// Product
static const String product = '/api/v1/products';
}

View File

@ -1,10 +0,0 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'analytic.freezed.dart';
part 'entities/sales_analytic_entity.dart';
part 'entities/profit_loss_analytic_entity.dart';
part 'entities/category_analytic_entity.dart';
part 'failures/analytic_failure.dart';

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +0,0 @@
part of '../analytic.dart';
@freezed
class CategoryAnalytic with _$CategoryAnalytic {
const factory CategoryAnalytic({
required String organizationId,
required String outletId,
required String dateFrom,
required String dateTo,
required List<CategoryAnalyticItem> data,
}) = _CategoryAnalytic;
factory CategoryAnalytic.empty() => const CategoryAnalytic(
organizationId: "",
outletId: "",
dateFrom: "",
dateTo: "",
data: [],
);
}
@freezed
class CategoryAnalyticItem with _$CategoryAnalyticItem {
const factory CategoryAnalyticItem({
required String categoryId,
required String categoryName,
required int totalRevenue,
required int totalQuantity,
required int productCount,
required int orderCount,
}) = _CategoryAnalyticItem;
factory CategoryAnalyticItem.empty() => const CategoryAnalyticItem(
categoryId: "",
categoryName: "",
totalRevenue: 0,
totalQuantity: 0,
productCount: 0,
orderCount: 0,
);
}

View File

@ -1,117 +0,0 @@
part of '../analytic.dart';
@freezed
class ProfitLossAnalytic with _$ProfitLossAnalytic {
const factory ProfitLossAnalytic({
required String organizationId,
required String dateFrom,
required String dateTo,
required String groupBy,
required ProfitLossSummary summary,
required List<ProfitLossDailyData> data,
required List<ProfitLossProductData> productData,
}) = _ProfitLossAnalytic;
factory ProfitLossAnalytic.empty() => ProfitLossAnalytic(
organizationId: '',
dateFrom: '',
dateTo: '',
groupBy: '',
summary: ProfitLossSummary.empty(),
data: [],
productData: [],
);
}
@freezed
class ProfitLossSummary with _$ProfitLossSummary {
const factory ProfitLossSummary({
required int totalRevenue,
required int totalCost,
required int grossProfit,
required double grossProfitMargin,
required int totalTax,
required int totalDiscount,
required int netProfit,
required double netProfitMargin,
required int totalOrders,
required double averageProfit,
required double profitabilityRatio,
}) = _ProfitLossSummary;
factory ProfitLossSummary.empty() => ProfitLossSummary(
totalRevenue: 0,
totalCost: 0,
grossProfit: 0,
grossProfitMargin: 0,
totalTax: 0,
totalDiscount: 0,
netProfit: 0,
netProfitMargin: 0,
totalOrders: 0,
averageProfit: 0,
profitabilityRatio: 0,
);
}
@freezed
class ProfitLossDailyData with _$ProfitLossDailyData {
const factory ProfitLossDailyData({
required String date,
required int revenue,
required int cost,
required int grossProfit,
required double grossProfitMargin,
required int tax,
required int discount,
required int netProfit,
required double netProfitMargin,
required int orders,
}) = _ProfitLossDailyData;
factory ProfitLossDailyData.empty() => ProfitLossDailyData(
date: '',
revenue: 0,
cost: 0,
grossProfit: 0,
grossProfitMargin: 0,
tax: 0,
discount: 0,
netProfit: 0,
netProfitMargin: 0,
orders: 0,
);
}
@freezed
class ProfitLossProductData with _$ProfitLossProductData {
const factory ProfitLossProductData({
required String productId,
required String productName,
required String categoryId,
required String categoryName,
required int quantitySold,
required int revenue,
required int cost,
required int grossProfit,
required double grossProfitMargin,
required int averagePrice,
required int averageCost,
required int profitPerUnit,
}) = _ProfitLossProductData;
factory ProfitLossProductData.empty() => ProfitLossProductData(
productId: '',
productName: '',
categoryId: '',
categoryName: '',
quantitySold: 0,
revenue: 0,
cost: 0,
grossProfit: 0,
grossProfitMargin: 0,
averagePrice: 0,
averageCost: 0,
profitPerUnit: 0,
);
}

View File

@ -1,70 +0,0 @@
part of '../analytic.dart';
@freezed
class SalesAnalytic with _$SalesAnalytic {
const factory SalesAnalytic({
required String organizationId,
required String outletId,
required DateTime dateFrom,
required DateTime dateTo,
required String groupBy,
required SalesAnalyticSummary summary,
required List<SalesAnalyticData> data,
}) = _SalesAnalytic;
factory SalesAnalytic.empty() => SalesAnalytic(
organizationId: '',
outletId: '',
dateFrom: DateTime.fromMillisecondsSinceEpoch(0),
dateTo: DateTime.fromMillisecondsSinceEpoch(0),
groupBy: '',
summary: SalesAnalyticSummary.empty(),
data: [],
);
}
@freezed
class SalesAnalyticSummary with _$SalesAnalyticSummary {
const factory SalesAnalyticSummary({
required int totalSales,
required int totalOrders,
required int totalItems,
required double averageOrderValue,
required int totalTax,
required int totalDiscount,
required int netSales,
}) = _SalesAnalyticSummary;
factory SalesAnalyticSummary.empty() => const SalesAnalyticSummary(
totalSales: 0,
totalOrders: 0,
totalItems: 0,
averageOrderValue: 0,
totalTax: 0,
totalDiscount: 0,
netSales: 0,
);
}
@freezed
class SalesAnalyticData with _$SalesAnalyticData {
const factory SalesAnalyticData({
required DateTime date,
required int sales,
required int orders,
required int items,
required int tax,
required int discount,
required int netSales,
}) = _SalesAnalyticData;
factory SalesAnalyticData.empty() => SalesAnalyticData(
date: DateTime.fromMillisecondsSinceEpoch(0),
sales: 0,
orders: 0,
items: 0,
tax: 0,
discount: 0,
netSales: 0,
);
}

View File

@ -1,10 +0,0 @@
part of '../analytic.dart';
@freezed
sealed class AnalyticFailure with _$AnalyticFailure {
const factory AnalyticFailure.serverError(ApiFailure failure) = _ServerError;
const factory AnalyticFailure.unexpectedError() = _UnexpectedError;
const factory AnalyticFailure.empty() = _Empty;
const factory AnalyticFailure.dynamicErrorMessage(String erroMessage) =
_DynamicErrorMessage;
}

View File

@ -1,20 +0,0 @@
import 'package:dartz/dartz.dart';
import '../analytic.dart';
abstract class IAnalyticRepository {
Future<Either<AnalyticFailure, SalesAnalytic>> getSales({
required DateTime dateFrom,
required DateTime dateTo,
});
Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({
required DateTime dateFrom,
required DateTime dateTo,
});
Future<Either<AnalyticFailure, CategoryAnalytic>> getCategory({
required DateTime dateFrom,
required DateTime dateTo,
});
}

View File

@ -1,10 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'category.freezed.dart';
part 'entities/category_entity.dart';
part 'failures/category_failure.dart';
part 'repositories/i_auth_repository.dart';

View File

@ -1,952 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'category.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$Category {
String get id => throw _privateConstructorUsedError;
String get organizationId => throw _privateConstructorUsedError;
String get name => throw _privateConstructorUsedError;
String get description => throw _privateConstructorUsedError;
String get businessType => throw _privateConstructorUsedError;
Map<String, dynamic> get metadata => throw _privateConstructorUsedError;
DateTime? get createdAt => throw _privateConstructorUsedError;
DateTime? get updatedAt => throw _privateConstructorUsedError;
/// Create a copy of Category
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CategoryCopyWith<Category> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryCopyWith<$Res> {
factory $CategoryCopyWith(Category value, $Res Function(Category) then) =
_$CategoryCopyWithImpl<$Res, Category>;
@useResult
$Res call({
String id,
String organizationId,
String name,
String description,
String businessType,
Map<String, dynamic> metadata,
DateTime? createdAt,
DateTime? updatedAt,
});
}
/// @nodoc
class _$CategoryCopyWithImpl<$Res, $Val extends Category>
implements $CategoryCopyWith<$Res> {
_$CategoryCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Category
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? organizationId = null,
Object? name = null,
Object? description = null,
Object? businessType = null,
Object? metadata = null,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String,
organizationId: null == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
description: null == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String,
businessType: null == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String,
metadata: null == metadata
? _value.metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$CategoryImplCopyWith<$Res>
implements $CategoryCopyWith<$Res> {
factory _$$CategoryImplCopyWith(
_$CategoryImpl value,
$Res Function(_$CategoryImpl) then,
) = __$$CategoryImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
String id,
String organizationId,
String name,
String description,
String businessType,
Map<String, dynamic> metadata,
DateTime? createdAt,
DateTime? updatedAt,
});
}
/// @nodoc
class __$$CategoryImplCopyWithImpl<$Res>
extends _$CategoryCopyWithImpl<$Res, _$CategoryImpl>
implements _$$CategoryImplCopyWith<$Res> {
__$$CategoryImplCopyWithImpl(
_$CategoryImpl _value,
$Res Function(_$CategoryImpl) _then,
) : super(_value, _then);
/// Create a copy of Category
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? organizationId = null,
Object? name = null,
Object? description = null,
Object? businessType = null,
Object? metadata = null,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$CategoryImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String,
organizationId: null == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
description: null == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String,
businessType: null == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String,
metadata: null == metadata
? _value._metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
),
);
}
}
/// @nodoc
class _$CategoryImpl implements _Category {
const _$CategoryImpl({
required this.id,
required this.organizationId,
required this.name,
required this.description,
required this.businessType,
required final Map<String, dynamic> metadata,
this.createdAt,
this.updatedAt,
}) : _metadata = metadata;
@override
final String id;
@override
final String organizationId;
@override
final String name;
@override
final String description;
@override
final String businessType;
final Map<String, dynamic> _metadata;
@override
Map<String, dynamic> get metadata {
if (_metadata is EqualUnmodifiableMapView) return _metadata;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(_metadata);
}
@override
final DateTime? createdAt;
@override
final DateTime? updatedAt;
@override
String toString() {
return 'Category(id: $id, organizationId: $organizationId, name: $name, description: $description, businessType: $businessType, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CategoryImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.organizationId, organizationId) ||
other.organizationId == organizationId) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.description, description) ||
other.description == description) &&
(identical(other.businessType, businessType) ||
other.businessType == businessType) &&
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt));
}
@override
int get hashCode => Object.hash(
runtimeType,
id,
organizationId,
name,
description,
businessType,
const DeepCollectionEquality().hash(_metadata),
createdAt,
updatedAt,
);
/// Create a copy of Category
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CategoryImplCopyWith<_$CategoryImpl> get copyWith =>
__$$CategoryImplCopyWithImpl<_$CategoryImpl>(this, _$identity);
}
abstract class _Category implements Category {
const factory _Category({
required final String id,
required final String organizationId,
required final String name,
required final String description,
required final String businessType,
required final Map<String, dynamic> metadata,
final DateTime? createdAt,
final DateTime? updatedAt,
}) = _$CategoryImpl;
@override
String get id;
@override
String get organizationId;
@override
String get name;
@override
String get description;
@override
String get businessType;
@override
Map<String, dynamic> get metadata;
@override
DateTime? get createdAt;
@override
DateTime? get updatedAt;
/// Create a copy of Category
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CategoryImplCopyWith<_$CategoryImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$CategoryFailure {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function() empty,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function()? empty,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function()? empty,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_Empty value) empty,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_Empty value)? empty,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_Empty value)? empty,
TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryFailureCopyWith<$Res> {
factory $CategoryFailureCopyWith(
CategoryFailure value,
$Res Function(CategoryFailure) then,
) = _$CategoryFailureCopyWithImpl<$Res, CategoryFailure>;
}
/// @nodoc
class _$CategoryFailureCopyWithImpl<$Res, $Val extends CategoryFailure>
implements $CategoryFailureCopyWith<$Res> {
_$CategoryFailureCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$ServerErrorImplCopyWith<$Res> {
factory _$$ServerErrorImplCopyWith(
_$ServerErrorImpl value,
$Res Function(_$ServerErrorImpl) then,
) = __$$ServerErrorImplCopyWithImpl<$Res>;
@useResult
$Res call({ApiFailure failure});
$ApiFailureCopyWith<$Res> get failure;
}
/// @nodoc
class __$$ServerErrorImplCopyWithImpl<$Res>
extends _$CategoryFailureCopyWithImpl<$Res, _$ServerErrorImpl>
implements _$$ServerErrorImplCopyWith<$Res> {
__$$ServerErrorImplCopyWithImpl(
_$ServerErrorImpl _value,
$Res Function(_$ServerErrorImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? failure = null}) {
return _then(
_$ServerErrorImpl(
null == failure
? _value.failure
: failure // ignore: cast_nullable_to_non_nullable
as ApiFailure,
),
);
}
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$ApiFailureCopyWith<$Res> get failure {
return $ApiFailureCopyWith<$Res>(_value.failure, (value) {
return _then(_value.copyWith(failure: value));
});
}
}
/// @nodoc
class _$ServerErrorImpl implements _ServerError {
const _$ServerErrorImpl(this.failure);
@override
final ApiFailure failure;
@override
String toString() {
return 'CategoryFailure.serverError(failure: $failure)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ServerErrorImpl &&
(identical(other.failure, failure) || other.failure == failure));
}
@override
int get hashCode => Object.hash(runtimeType, failure);
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ServerErrorImplCopyWith<_$ServerErrorImpl> get copyWith =>
__$$ServerErrorImplCopyWithImpl<_$ServerErrorImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function() empty,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return serverError(failure);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function()? empty,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return serverError?.call(failure);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function()? empty,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (serverError != null) {
return serverError(failure);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_Empty value) empty,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return serverError(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_Empty value)? empty,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return serverError?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_Empty value)? empty,
TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (serverError != null) {
return serverError(this);
}
return orElse();
}
}
abstract class _ServerError implements CategoryFailure {
const factory _ServerError(final ApiFailure failure) = _$ServerErrorImpl;
ApiFailure get failure;
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ServerErrorImplCopyWith<_$ServerErrorImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$UnexpectedErrorImplCopyWith<$Res> {
factory _$$UnexpectedErrorImplCopyWith(
_$UnexpectedErrorImpl value,
$Res Function(_$UnexpectedErrorImpl) then,
) = __$$UnexpectedErrorImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$UnexpectedErrorImplCopyWithImpl<$Res>
extends _$CategoryFailureCopyWithImpl<$Res, _$UnexpectedErrorImpl>
implements _$$UnexpectedErrorImplCopyWith<$Res> {
__$$UnexpectedErrorImplCopyWithImpl(
_$UnexpectedErrorImpl _value,
$Res Function(_$UnexpectedErrorImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$UnexpectedErrorImpl implements _UnexpectedError {
const _$UnexpectedErrorImpl();
@override
String toString() {
return 'CategoryFailure.unexpectedError()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$UnexpectedErrorImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function() empty,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return unexpectedError();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function()? empty,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return unexpectedError?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function()? empty,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (unexpectedError != null) {
return unexpectedError();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_Empty value) empty,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return unexpectedError(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_Empty value)? empty,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return unexpectedError?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_Empty value)? empty,
TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (unexpectedError != null) {
return unexpectedError(this);
}
return orElse();
}
}
abstract class _UnexpectedError implements CategoryFailure {
const factory _UnexpectedError() = _$UnexpectedErrorImpl;
}
/// @nodoc
abstract class _$$EmptyImplCopyWith<$Res> {
factory _$$EmptyImplCopyWith(
_$EmptyImpl value,
$Res Function(_$EmptyImpl) then,
) = __$$EmptyImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$EmptyImplCopyWithImpl<$Res>
extends _$CategoryFailureCopyWithImpl<$Res, _$EmptyImpl>
implements _$$EmptyImplCopyWith<$Res> {
__$$EmptyImplCopyWithImpl(
_$EmptyImpl _value,
$Res Function(_$EmptyImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$EmptyImpl implements _Empty {
const _$EmptyImpl();
@override
String toString() {
return 'CategoryFailure.empty()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$EmptyImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function() empty,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return empty();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function()? empty,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return empty?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function()? empty,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (empty != null) {
return empty();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_Empty value) empty,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return empty(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_Empty value)? empty,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return empty?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_Empty value)? empty,
TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (empty != null) {
return empty(this);
}
return orElse();
}
}
abstract class _Empty implements CategoryFailure {
const factory _Empty() = _$EmptyImpl;
}
/// @nodoc
abstract class _$$DynamicErrorMessageImplCopyWith<$Res> {
factory _$$DynamicErrorMessageImplCopyWith(
_$DynamicErrorMessageImpl value,
$Res Function(_$DynamicErrorMessageImpl) then,
) = __$$DynamicErrorMessageImplCopyWithImpl<$Res>;
@useResult
$Res call({String erroMessage});
}
/// @nodoc
class __$$DynamicErrorMessageImplCopyWithImpl<$Res>
extends _$CategoryFailureCopyWithImpl<$Res, _$DynamicErrorMessageImpl>
implements _$$DynamicErrorMessageImplCopyWith<$Res> {
__$$DynamicErrorMessageImplCopyWithImpl(
_$DynamicErrorMessageImpl _value,
$Res Function(_$DynamicErrorMessageImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? erroMessage = null}) {
return _then(
_$DynamicErrorMessageImpl(
null == erroMessage
? _value.erroMessage
: erroMessage // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$DynamicErrorMessageImpl implements _DynamicErrorMessage {
const _$DynamicErrorMessageImpl(this.erroMessage);
@override
final String erroMessage;
@override
String toString() {
return 'CategoryFailure.dynamicErrorMessage(erroMessage: $erroMessage)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$DynamicErrorMessageImpl &&
(identical(other.erroMessage, erroMessage) ||
other.erroMessage == erroMessage));
}
@override
int get hashCode => Object.hash(runtimeType, erroMessage);
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$DynamicErrorMessageImplCopyWith<_$DynamicErrorMessageImpl> get copyWith =>
__$$DynamicErrorMessageImplCopyWithImpl<_$DynamicErrorMessageImpl>(
this,
_$identity,
);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function() empty,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return dynamicErrorMessage(erroMessage);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function()? empty,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return dynamicErrorMessage?.call(erroMessage);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function()? empty,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (dynamicErrorMessage != null) {
return dynamicErrorMessage(erroMessage);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_Empty value) empty,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return dynamicErrorMessage(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_Empty value)? empty,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return dynamicErrorMessage?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_Empty value)? empty,
TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (dynamicErrorMessage != null) {
return dynamicErrorMessage(this);
}
return orElse();
}
}
abstract class _DynamicErrorMessage implements CategoryFailure {
const factory _DynamicErrorMessage(final String erroMessage) =
_$DynamicErrorMessageImpl;
String get erroMessage;
/// Create a copy of CategoryFailure
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$DynamicErrorMessageImplCopyWith<_$DynamicErrorMessageImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,33 +0,0 @@
part of '../category.dart';
@freezed
class Category with _$Category {
const factory Category({
required String id,
required String organizationId,
required String name,
required String description,
required String businessType,
required Map<String, dynamic> metadata,
DateTime? createdAt,
DateTime? updatedAt,
}) = _Category;
factory Category.empty() => const Category(
id: '',
organizationId: '',
name: '',
description: '',
businessType: '',
metadata: {},
);
factory Category.addAllData() => Category(
id: 'all',
organizationId: '',
name: 'Semua',
description: '',
businessType: '',
metadata: {},
);
}

View File

@ -1,10 +0,0 @@
part of '../category.dart';
@freezed
sealed class CategoryFailure with _$CategoryFailure {
const factory CategoryFailure.serverError(ApiFailure failure) = _ServerError;
const factory CategoryFailure.unexpectedError() = _UnexpectedError;
const factory CategoryFailure.empty() = _Empty;
const factory CategoryFailure.dynamicErrorMessage(String erroMessage) =
_DynamicErrorMessage;
}

View File

@ -1,9 +0,0 @@
part of '../category.dart';
abstract class ICategoryRepository {
Future<Either<CategoryFailure, List<Category>>> get({
int page = 1,
int limit = 20,
bool isActive = true,
});
}

View File

@ -1,43 +0,0 @@
part of '../product.dart';
@freezed
class Product with _$Product {
const factory Product({
required String id,
required String organizationId,
required String categoryId,
required String sku,
required String name,
required String description,
required int price,
required int cost,
required String businessType,
required String imageUrl,
required String printerType,
required Map<String, dynamic> metadata,
required bool isActive,
required DateTime createdAt,
required DateTime updatedAt,
required List<ProductVariant> variants,
}) = _Product;
/// âś… factory kosong untuk default state
factory Product.empty() => Product(
id: '',
organizationId: '',
categoryId: '',
sku: '',
name: '',
description: '',
price: 0,
cost: 0,
businessType: '',
imageUrl: '',
printerType: '',
metadata: {},
isActive: false,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
variants: [],
);
}

View File

@ -1,26 +0,0 @@
part of '../product.dart';
@freezed
class ProductVariant with _$ProductVariant {
const factory ProductVariant({
required String id,
required String productId,
required String name,
required int priceModifier,
required int cost,
required Map<String, dynamic> metadata,
required DateTime createdAt,
required DateTime updatedAt,
}) = _ProductVariant;
factory ProductVariant.empty() => ProductVariant(
id: '',
productId: '',
name: '',
priceModifier: 0,
cost: 0,
metadata: {},
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
}

View File

@ -1,10 +0,0 @@
part of '../product.dart';
@freezed
sealed class ProductFailure with _$ProductFailure {
const factory ProductFailure.serverError(ApiFailure failure) = _ServerError;
const factory ProductFailure.unexpectedError() = _UnexpectedError;
const factory ProductFailure.empty() = _Empty;
const factory ProductFailure.dynamicErrorMessage(String erroMessage) =
_DynamicErrorMessage;
}

View File

@ -1,11 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'product.freezed.dart';
part 'entities/product_entity.dart';
part 'entities/product_variant_entity.dart';
part 'failures/product_failure.dart';
part 'repositories/i_product_repository.dart';

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +0,0 @@
part of '../product.dart';
abstract class IProductRepository {
Future<Either<ProductFailure, List<Product>>> get({
int page = 1,
int limit = 10,
String? categoryId,
String? search,
});
}

View File

@ -1,10 +0,0 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/analytic/analytic.dart';
part 'analytic_dtos.freezed.dart';
part 'analytic_dtos.g.dart';
part 'dto/sales_analytic_dto.dart';
part 'dto/profit_loss_analytic_dto.dart';
part 'dto/category_analytic_dto.dart';

File diff suppressed because it is too large Load Diff

View File

@ -1,259 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'analytic_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$SalesAnalyticDtoImpl _$$SalesAnalyticDtoImplFromJson(
Map<String, dynamic> json,
) => _$SalesAnalyticDtoImpl(
organizationId: json['organization_id'] as String?,
outletId: json['outlet_id'] as String?,
dateFrom: json['date_from'] == null
? null
: DateTime.parse(json['date_from'] as String),
dateTo: json['date_to'] == null
? null
: DateTime.parse(json['date_to'] as String),
groupBy: json['group_by'] as String?,
summary: json['summary'] == null
? null
: SalesAnalyticSummaryDto.fromJson(
json['summary'] as Map<String, dynamic>,
),
data: (json['data'] as List<dynamic>?)
?.map((e) => SalesAnalyticDataDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$SalesAnalyticDtoImplToJson(
_$SalesAnalyticDtoImpl instance,
) => <String, dynamic>{
'organization_id': instance.organizationId,
'outlet_id': instance.outletId,
'date_from': instance.dateFrom?.toIso8601String(),
'date_to': instance.dateTo?.toIso8601String(),
'group_by': instance.groupBy,
'summary': instance.summary,
'data': instance.data,
};
_$SalesAnalyticSummaryDtoImpl _$$SalesAnalyticSummaryDtoImplFromJson(
Map<String, dynamic> json,
) => _$SalesAnalyticSummaryDtoImpl(
totalSales: json['total_sales'] as num?,
totalOrders: json['total_orders'] as num?,
totalItems: json['total_items'] as num?,
averageOrderValue: json['average_order_value'] as num?,
totalTax: json['total_tax'] as num?,
totalDiscount: json['total_discount'] as num?,
netSales: json['net_sales'] as num?,
);
Map<String, dynamic> _$$SalesAnalyticSummaryDtoImplToJson(
_$SalesAnalyticSummaryDtoImpl instance,
) => <String, dynamic>{
'total_sales': instance.totalSales,
'total_orders': instance.totalOrders,
'total_items': instance.totalItems,
'average_order_value': instance.averageOrderValue,
'total_tax': instance.totalTax,
'total_discount': instance.totalDiscount,
'net_sales': instance.netSales,
};
_$SalesAnalyticDataDtoImpl _$$SalesAnalyticDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$SalesAnalyticDataDtoImpl(
date: json['date'] == null ? null : DateTime.parse(json['date'] as String),
sales: json['sales'] as num?,
orders: json['orders'] as num?,
items: json['items'] as num?,
tax: json['tax'] as num?,
discount: json['discount'] as num?,
netSales: json['net_sales'] as num?,
);
Map<String, dynamic> _$$SalesAnalyticDataDtoImplToJson(
_$SalesAnalyticDataDtoImpl instance,
) => <String, dynamic>{
'date': instance.date?.toIso8601String(),
'sales': instance.sales,
'orders': instance.orders,
'items': instance.items,
'tax': instance.tax,
'discount': instance.discount,
'net_sales': instance.netSales,
};
_$ProfitLossAnalyticDtoImpl _$$ProfitLossAnalyticDtoImplFromJson(
Map<String, dynamic> json,
) => _$ProfitLossAnalyticDtoImpl(
organizationId: json['organization_id'] as String?,
dateFrom: json['date_from'] as String?,
dateTo: json['date_to'] as String?,
groupBy: json['group_by'] as String?,
summary: json['summary'] == null
? null
: ProfitLossSummaryDto.fromJson(json['summary'] as Map<String, dynamic>),
data: (json['data'] as List<dynamic>?)
?.map((e) => ProfitLossDailyDataDto.fromJson(e as Map<String, dynamic>))
.toList(),
productData: (json['product_data'] as List<dynamic>?)
?.map((e) => ProfitLossProductDataDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$ProfitLossAnalyticDtoImplToJson(
_$ProfitLossAnalyticDtoImpl instance,
) => <String, dynamic>{
'organization_id': instance.organizationId,
'date_from': instance.dateFrom,
'date_to': instance.dateTo,
'group_by': instance.groupBy,
'summary': instance.summary,
'data': instance.data,
'product_data': instance.productData,
};
_$ProfitLossSummaryDtoImpl _$$ProfitLossSummaryDtoImplFromJson(
Map<String, dynamic> json,
) => _$ProfitLossSummaryDtoImpl(
totalRevenue: (json['total_revenue'] as num?)?.toInt(),
totalCost: (json['total_cost'] as num?)?.toInt(),
grossProfit: (json['gross_profit'] as num?)?.toInt(),
grossProfitMargin: (json['gross_profit_margin'] as num?)?.toDouble(),
totalTax: (json['total_tax'] as num?)?.toInt(),
totalDiscount: (json['total_discount'] as num?)?.toInt(),
netProfit: (json['net_profit'] as num?)?.toInt(),
netProfitMargin: (json['net_profit_margin'] as num?)?.toDouble(),
totalOrders: (json['total_orders'] as num?)?.toInt(),
averageProfit: (json['average_profit'] as num?)?.toDouble(),
profitabilityRatio: (json['profitability_ratio'] as num?)?.toDouble(),
);
Map<String, dynamic> _$$ProfitLossSummaryDtoImplToJson(
_$ProfitLossSummaryDtoImpl instance,
) => <String, dynamic>{
'total_revenue': instance.totalRevenue,
'total_cost': instance.totalCost,
'gross_profit': instance.grossProfit,
'gross_profit_margin': instance.grossProfitMargin,
'total_tax': instance.totalTax,
'total_discount': instance.totalDiscount,
'net_profit': instance.netProfit,
'net_profit_margin': instance.netProfitMargin,
'total_orders': instance.totalOrders,
'average_profit': instance.averageProfit,
'profitability_ratio': instance.profitabilityRatio,
};
_$ProfitLossDailyDataDtoImpl _$$ProfitLossDailyDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$ProfitLossDailyDataDtoImpl(
date: json['date'] as String?,
revenue: (json['revenue'] as num?)?.toInt(),
cost: (json['cost'] as num?)?.toInt(),
grossProfit: (json['gross_profit'] as num?)?.toInt(),
grossProfitMargin: (json['gross_profit_margin'] as num?)?.toDouble(),
tax: (json['tax'] as num?)?.toInt(),
discount: (json['discount'] as num?)?.toInt(),
netProfit: (json['net_profit'] as num?)?.toInt(),
netProfitMargin: (json['net_profit_margin'] as num?)?.toDouble(),
orders: (json['orders'] as num?)?.toInt(),
);
Map<String, dynamic> _$$ProfitLossDailyDataDtoImplToJson(
_$ProfitLossDailyDataDtoImpl instance,
) => <String, dynamic>{
'date': instance.date,
'revenue': instance.revenue,
'cost': instance.cost,
'gross_profit': instance.grossProfit,
'gross_profit_margin': instance.grossProfitMargin,
'tax': instance.tax,
'discount': instance.discount,
'net_profit': instance.netProfit,
'net_profit_margin': instance.netProfitMargin,
'orders': instance.orders,
};
_$ProfitLossProductDataDtoImpl _$$ProfitLossProductDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$ProfitLossProductDataDtoImpl(
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(),
cost: (json['cost'] as num?)?.toInt(),
grossProfit: (json['gross_profit'] as num?)?.toInt(),
grossProfitMargin: (json['gross_profit_margin'] as num?)?.toDouble(),
averagePrice: (json['average_price'] as num?)?.toInt(),
averageCost: (json['average_cost'] as num?)?.toInt(),
profitPerUnit: (json['profit_per_unit'] as num?)?.toInt(),
);
Map<String, dynamic> _$$ProfitLossProductDataDtoImplToJson(
_$ProfitLossProductDataDtoImpl instance,
) => <String, dynamic>{
'product_id': instance.productId,
'product_name': instance.productName,
'category_id': instance.categoryId,
'category_name': instance.categoryName,
'quantity_sold': instance.quantitySold,
'revenue': instance.revenue,
'cost': instance.cost,
'gross_profit': instance.grossProfit,
'gross_profit_margin': instance.grossProfitMargin,
'average_price': instance.averagePrice,
'average_cost': instance.averageCost,
'profit_per_unit': instance.profitPerUnit,
};
_$CategoryAnalyticDtoImpl _$$CategoryAnalyticDtoImplFromJson(
Map<String, dynamic> json,
) => _$CategoryAnalyticDtoImpl(
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<dynamic>?)
?.map((e) => CategoryAnalyticItemDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$CategoryAnalyticDtoImplToJson(
_$CategoryAnalyticDtoImpl instance,
) => <String, dynamic>{
'organization_id': instance.organizationId,
'outlet_id': instance.outletId,
'date_from': instance.dateFrom,
'date_to': instance.dateTo,
'data': instance.data,
};
_$CategoryAnalyticItemDtoImpl _$$CategoryAnalyticItemDtoImplFromJson(
Map<String, dynamic> json,
) => _$CategoryAnalyticItemDtoImpl(
categoryId: json['category_id'] as String?,
categoryName: json['category_name'] as String?,
totalRevenue: (json['total_revenue'] as num?)?.toInt(),
totalQuantity: (json['total_quantity'] as num?)?.toInt(),
productCount: (json['product_count'] as num?)?.toInt(),
orderCount: (json['order_count'] as num?)?.toInt(),
);
Map<String, dynamic> _$$CategoryAnalyticItemDtoImplToJson(
_$CategoryAnalyticItemDtoImpl instance,
) => <String, dynamic>{
'category_id': instance.categoryId,
'category_name': instance.categoryName,
'total_revenue': instance.totalRevenue,
'total_quantity': instance.totalQuantity,
'product_count': instance.productCount,
'order_count': instance.orderCount,
};

View File

@ -1,101 +0,0 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/extension/extension.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/analytic/analytic.dart';
import '../analytic_dtos.dart';
@injectable
class AnalyticRemoteDataProvider {
final ApiClient _apiClient;
final String _logName = "AnalyticRemoteDataProvider";
AnalyticRemoteDataProvider(this._apiClient);
Future<DC<AnalyticFailure, SalesAnalyticDto>> fetchSales({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final response = await _apiClient.get(
ApiPath.salesAnalytic,
params: {
'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate,
},
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(AnalyticFailure.empty());
}
final dto = SalesAnalyticDto.fromJson(response.data['data']);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchSalesError', name: _logName, error: e, stackTrace: s);
return DC.error(AnalyticFailure.serverError(e));
}
}
Future<DC<AnalyticFailure, ProfitLossAnalyticDto>> fetchProfitLoss({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final response = await _apiClient.get(
ApiPath.profitLossAnalytic,
params: {
'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate,
},
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(AnalyticFailure.empty());
}
final dto = ProfitLossAnalyticDto.fromJson(response.data['data']);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchProfitLossError', name: _logName, error: e, stackTrace: s);
return DC.error(AnalyticFailure.serverError(e));
}
}
Future<DC<AnalyticFailure, CategoryAnalyticDto>> fetchCategory({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final response = await _apiClient.get(
ApiPath.categoryAnalytic,
params: {
'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate,
},
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(AnalyticFailure.empty());
}
final dto = CategoryAnalyticDto.fromJson(response.data['data']);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchCategoryError', name: _logName, error: e, stackTrace: s);
return DC.error(AnalyticFailure.serverError(e));
}
}
}

View File

@ -1,51 +0,0 @@
part of '../analytic_dtos.dart';
@freezed
class CategoryAnalyticDto with _$CategoryAnalyticDto {
const CategoryAnalyticDto._();
const factory CategoryAnalyticDto({
@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<CategoryAnalyticItemDto>? data,
}) = _CategoryAnalyticDto;
factory CategoryAnalyticDto.fromJson(Map<String, dynamic> json) =>
_$CategoryAnalyticDtoFromJson(json);
CategoryAnalytic toDomain() => CategoryAnalytic(
organizationId: organizationId ?? "",
outletId: outletId ?? "",
dateFrom: dateFrom ?? "",
dateTo: dateTo ?? "",
data: data?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class CategoryAnalyticItemDto with _$CategoryAnalyticItemDto {
const CategoryAnalyticItemDto._();
const factory CategoryAnalyticItemDto({
@JsonKey(name: 'category_id') String? categoryId,
@JsonKey(name: 'category_name') String? categoryName,
@JsonKey(name: 'total_revenue') int? totalRevenue,
@JsonKey(name: 'total_quantity') int? totalQuantity,
@JsonKey(name: 'product_count') int? productCount,
@JsonKey(name: 'order_count') int? orderCount,
}) = _CategoryAnalyticItemDto;
factory CategoryAnalyticItemDto.fromJson(Map<String, dynamic> json) =>
_$CategoryAnalyticItemDtoFromJson(json);
CategoryAnalyticItem toDomain() => CategoryAnalyticItem(
categoryId: categoryId ?? "",
categoryName: categoryName ?? "",
totalRevenue: totalRevenue ?? 0,
totalQuantity: totalQuantity ?? 0,
productCount: productCount ?? 0,
orderCount: orderCount ?? 0,
);
}

View File

@ -1,137 +0,0 @@
part of '../analytic_dtos.dart';
@freezed
class ProfitLossAnalyticDto with _$ProfitLossAnalyticDto {
const ProfitLossAnalyticDto._();
const factory ProfitLossAnalyticDto({
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'date_from') String? dateFrom,
@JsonKey(name: 'date_to') String? dateTo,
@JsonKey(name: 'group_by') String? groupBy,
@JsonKey(name: 'summary') ProfitLossSummaryDto? summary,
@JsonKey(name: 'data') List<ProfitLossDailyDataDto>? data,
@JsonKey(name: 'product_data') List<ProfitLossProductDataDto>? productData,
}) = _ProfitLossAnalyticDto;
factory ProfitLossAnalyticDto.fromJson(Map<String, dynamic> json) =>
_$ProfitLossAnalyticDtoFromJson(json);
ProfitLossAnalytic toDomain() => ProfitLossAnalytic(
organizationId: organizationId ?? '',
dateFrom: dateFrom ?? '',
dateTo: dateTo ?? '',
groupBy: groupBy ?? '',
summary: summary?.toDomain() ?? ProfitLossSummary.empty(),
data: (data ?? []).map((e) => e.toDomain()).toList(),
productData: (productData ?? []).map((e) => e.toDomain()).toList(),
);
}
@freezed
class ProfitLossSummaryDto with _$ProfitLossSummaryDto {
const ProfitLossSummaryDto._();
const factory ProfitLossSummaryDto({
@JsonKey(name: 'total_revenue') int? totalRevenue,
@JsonKey(name: 'total_cost') int? totalCost,
@JsonKey(name: 'gross_profit') int? grossProfit,
@JsonKey(name: 'gross_profit_margin') double? grossProfitMargin,
@JsonKey(name: 'total_tax') int? totalTax,
@JsonKey(name: 'total_discount') int? totalDiscount,
@JsonKey(name: 'net_profit') int? netProfit,
@JsonKey(name: 'net_profit_margin') double? netProfitMargin,
@JsonKey(name: 'total_orders') int? totalOrders,
@JsonKey(name: 'average_profit') double? averageProfit,
@JsonKey(name: 'profitability_ratio') double? profitabilityRatio,
}) = _ProfitLossSummaryDto;
factory ProfitLossSummaryDto.fromJson(Map<String, dynamic> json) =>
_$ProfitLossSummaryDtoFromJson(json);
ProfitLossSummary toDomain() => ProfitLossSummary(
totalRevenue: totalRevenue ?? 0,
totalCost: totalCost ?? 0,
grossProfit: grossProfit ?? 0,
grossProfitMargin: grossProfitMargin ?? 0.0,
totalTax: totalTax ?? 0,
totalDiscount: totalDiscount ?? 0,
netProfit: netProfit ?? 0,
netProfitMargin: netProfitMargin ?? 0.0,
totalOrders: totalOrders ?? 0,
averageProfit: averageProfit ?? 0.0,
profitabilityRatio: profitabilityRatio ?? 0.0,
);
}
@freezed
class ProfitLossDailyDataDto with _$ProfitLossDailyDataDto {
const ProfitLossDailyDataDto._();
const factory ProfitLossDailyDataDto({
@JsonKey(name: 'date') String? date,
@JsonKey(name: 'revenue') int? revenue,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'gross_profit') int? grossProfit,
@JsonKey(name: 'gross_profit_margin') double? grossProfitMargin,
@JsonKey(name: 'tax') int? tax,
@JsonKey(name: 'discount') int? discount,
@JsonKey(name: 'net_profit') int? netProfit,
@JsonKey(name: 'net_profit_margin') double? netProfitMargin,
@JsonKey(name: 'orders') int? orders,
}) = _ProfitLossDailyDataDto;
factory ProfitLossDailyDataDto.fromJson(Map<String, dynamic> json) =>
_$ProfitLossDailyDataDtoFromJson(json);
ProfitLossDailyData toDomain() => ProfitLossDailyData(
date: date ?? '',
revenue: revenue ?? 0,
cost: cost ?? 0,
grossProfit: grossProfit ?? 0,
grossProfitMargin: grossProfitMargin ?? 0.0,
tax: tax ?? 0,
discount: discount ?? 0,
netProfit: netProfit ?? 0,
netProfitMargin: netProfitMargin ?? 0.0,
orders: orders ?? 0,
);
}
@freezed
class ProfitLossProductDataDto with _$ProfitLossProductDataDto {
const ProfitLossProductDataDto._();
const factory ProfitLossProductDataDto({
@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: 'cost') int? cost,
@JsonKey(name: 'gross_profit') int? grossProfit,
@JsonKey(name: 'gross_profit_margin') double? grossProfitMargin,
@JsonKey(name: 'average_price') int? averagePrice,
@JsonKey(name: 'average_cost') int? averageCost,
@JsonKey(name: 'profit_per_unit') int? profitPerUnit,
}) = _ProfitLossProductDataDto;
factory ProfitLossProductDataDto.fromJson(Map<String, dynamic> json) =>
_$ProfitLossProductDataDtoFromJson(json);
ProfitLossProductData toDomain() => ProfitLossProductData(
productId: productId ?? '',
productName: productName ?? '',
categoryId: categoryId ?? '',
categoryName: categoryName ?? '',
quantitySold: quantitySold ?? 0,
revenue: revenue ?? 0,
cost: cost ?? 0,
grossProfit: grossProfit ?? 0,
grossProfitMargin: grossProfitMargin ?? 0.0,
averagePrice: averagePrice ?? 0,
averageCost: averageCost ?? 0,
profitPerUnit: profitPerUnit ?? 0,
);
}

View File

@ -1,85 +0,0 @@
part of '../analytic_dtos.dart';
@freezed
class SalesAnalyticDto with _$SalesAnalyticDto {
const SalesAnalyticDto._();
const factory SalesAnalyticDto({
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'outlet_id') String? outletId,
@JsonKey(name: 'date_from') DateTime? dateFrom,
@JsonKey(name: 'date_to') DateTime? dateTo,
@JsonKey(name: 'group_by') String? groupBy,
@JsonKey(name: 'summary') SalesAnalyticSummaryDto? summary,
@JsonKey(name: 'data') List<SalesAnalyticDataDto>? data,
}) = _SalesAnalyticDto;
factory SalesAnalyticDto.fromJson(Map<String, dynamic> json) =>
_$SalesAnalyticDtoFromJson(json);
SalesAnalytic toDomain() => SalesAnalytic(
organizationId: organizationId ?? '',
outletId: outletId ?? '',
dateFrom: dateFrom ?? DateTime.fromMillisecondsSinceEpoch(0),
dateTo: dateTo ?? DateTime.fromMillisecondsSinceEpoch(0),
groupBy: groupBy ?? '',
summary: summary?.toDomain() ?? SalesAnalyticSummary.empty(),
data: data?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class SalesAnalyticSummaryDto with _$SalesAnalyticSummaryDto {
const SalesAnalyticSummaryDto._();
const factory SalesAnalyticSummaryDto({
@JsonKey(name: 'total_sales') num? totalSales,
@JsonKey(name: 'total_orders') num? totalOrders,
@JsonKey(name: 'total_items') num? totalItems,
@JsonKey(name: 'average_order_value') num? averageOrderValue,
@JsonKey(name: 'total_tax') num? totalTax,
@JsonKey(name: 'total_discount') num? totalDiscount,
@JsonKey(name: 'net_sales') num? netSales,
}) = _SalesAnalyticSummaryDto;
factory SalesAnalyticSummaryDto.fromJson(Map<String, dynamic> json) =>
_$SalesAnalyticSummaryDtoFromJson(json);
SalesAnalyticSummary toDomain() => SalesAnalyticSummary(
totalSales: totalSales?.toInt() ?? 0,
totalOrders: totalOrders?.toInt() ?? 0,
totalItems: totalItems?.toInt() ?? 0,
averageOrderValue: averageOrderValue?.toDouble() ?? 0,
totalTax: totalTax?.toInt() ?? 0,
totalDiscount: totalDiscount?.toInt() ?? 0,
netSales: netSales?.toInt() ?? 0,
);
}
@freezed
class SalesAnalyticDataDto with _$SalesAnalyticDataDto {
const SalesAnalyticDataDto._();
const factory SalesAnalyticDataDto({
@JsonKey(name: 'date') DateTime? date,
@JsonKey(name: 'sales') num? sales,
@JsonKey(name: 'orders') num? orders,
@JsonKey(name: 'items') num? items,
@JsonKey(name: 'tax') num? tax,
@JsonKey(name: 'discount') num? discount,
@JsonKey(name: 'net_sales') num? netSales,
}) = _SalesAnalyticDataDto;
factory SalesAnalyticDataDto.fromJson(Map<String, dynamic> json) =>
_$SalesAnalyticDataDtoFromJson(json);
SalesAnalyticData toDomain() => SalesAnalyticData(
date: date ?? DateTime.fromMillisecondsSinceEpoch(0),
sales: sales?.toInt() ?? 0,
orders: orders?.toInt() ?? 0,
items: items?.toInt() ?? 0,
tax: tax?.toInt() ?? 0,
discount: discount?.toInt() ?? 0,
netSales: netSales?.toInt() ?? 0,
);
}

View File

@ -1,88 +0,0 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
import '../datasource/remote_data_provider.dart';
@Injectable(as: IAnalyticRepository)
class AnalyticRepository implements IAnalyticRepository {
final AnalyticRemoteDataProvider _dataProvider;
final String _logName = 'AnalyticRepository';
AnalyticRepository(this._dataProvider);
@override
Future<Either<AnalyticFailure, SalesAnalytic>> getSales({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final result = await _dataProvider.fetchSales(
dateFrom: dateFrom,
dateTo: dateTo,
);
if (result.hasError) {
return left(result.error!);
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) {
log('getSalesError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError());
}
}
@override
Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final result = await _dataProvider.fetchProfitLoss(
dateFrom: dateFrom,
dateTo: dateTo,
);
if (result.hasError) {
return left(result.error!);
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) {
log('getProfitLossError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError());
}
}
@override
Future<Either<AnalyticFailure, CategoryAnalytic>> getCategory({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final result = await _dataProvider.fetchCategory(
dateFrom: dateFrom,
dateTo: dateTo,
);
if (result.hasError) {
return left(result.error!);
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) {
log('getCategoryError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError());
}
}
}

View File

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:developer';
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -11,7 +10,6 @@ import '../auth_dtos.dart';
@injectable
class AuthLocalDataProvider {
final SharedPreferences _sharedPreferences;
final String _logName = 'AuthLocalDataProvider';
AuthLocalDataProvider(this._sharedPreferences);
@ -50,11 +48,7 @@ class AuthLocalDataProvider {
}
Future<void> deleteAllAuth() async {
try {
await _sharedPreferences.remove(LocalStorageKey.token);
await _sharedPreferences.remove(LocalStorageKey.user);
} catch (e) {
log('deleteAllAuthError', name: _logName, error: e);
}
await _sharedPreferences.remove(LocalStorageKey.token);
await _sharedPreferences.remove(LocalStorageKey.user);
}
}

View File

@ -6,7 +6,6 @@ import 'package:data_channel/data_channel.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/auth/auth.dart';
import '../auth_dtos.dart';
@ -46,7 +45,7 @@ class AuthRemoteDataProvider {
Future<DC<AuthFailure, Unit>> logout() async {
try {
await _apiClient.post(ApiPath.logout, headers: getAuthorizationHeader());
await _apiClient.post(ApiPath.logout);
return DC.data(unit);
} on ApiFailure catch (e, s) {
log('login', name: _logName, error: e, stackTrace: s);

View File

@ -1,8 +0,0 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/category/category.dart';
part 'category_dtos.freezed.dart';
part 'category_dtos.g.dart';
part 'dto/category_dto.dart';

View File

@ -1,368 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'category_dtos.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
CategoryDto _$CategoryDtoFromJson(Map<String, dynamic> json) {
return _CategoryDto.fromJson(json);
}
/// @nodoc
mixin _$CategoryDto {
@JsonKey(name: 'id')
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: 'organization_id')
String? get organizationId => throw _privateConstructorUsedError;
@JsonKey(name: 'name')
String? get name => throw _privateConstructorUsedError;
@JsonKey(name: 'description')
String? get description => throw _privateConstructorUsedError;
@JsonKey(name: 'business_type')
String? get businessType => throw _privateConstructorUsedError;
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
DateTime? get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: 'updated_at')
DateTime? get updatedAt => throw _privateConstructorUsedError;
/// Serializes this CategoryDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of CategoryDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CategoryDtoCopyWith<CategoryDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryDtoCopyWith<$Res> {
factory $CategoryDtoCopyWith(
CategoryDto value,
$Res Function(CategoryDto) then,
) = _$CategoryDtoCopyWithImpl<$Res, CategoryDto>;
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'description') String? description,
@JsonKey(name: 'business_type') String? businessType,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
});
}
/// @nodoc
class _$CategoryDtoCopyWithImpl<$Res, $Val extends CategoryDto>
implements $CategoryDtoCopyWith<$Res> {
_$CategoryDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? organizationId = freezed,
Object? name = freezed,
Object? description = freezed,
Object? businessType = freezed,
Object? metadata = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_value.copyWith(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
organizationId: freezed == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
description: freezed == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String?,
businessType: freezed == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String?,
metadata: freezed == metadata
? _value.metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$CategoryDtoImplCopyWith<$Res>
implements $CategoryDtoCopyWith<$Res> {
factory _$$CategoryDtoImplCopyWith(
_$CategoryDtoImpl value,
$Res Function(_$CategoryDtoImpl) then,
) = __$$CategoryDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'description') String? description,
@JsonKey(name: 'business_type') String? businessType,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
});
}
/// @nodoc
class __$$CategoryDtoImplCopyWithImpl<$Res>
extends _$CategoryDtoCopyWithImpl<$Res, _$CategoryDtoImpl>
implements _$$CategoryDtoImplCopyWith<$Res> {
__$$CategoryDtoImplCopyWithImpl(
_$CategoryDtoImpl _value,
$Res Function(_$CategoryDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of CategoryDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? organizationId = freezed,
Object? name = freezed,
Object? description = freezed,
Object? businessType = freezed,
Object? metadata = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$CategoryDtoImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
organizationId: freezed == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
description: freezed == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String?,
businessType: freezed == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String?,
metadata: freezed == metadata
? _value._metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$CategoryDtoImpl extends _CategoryDto {
const _$CategoryDtoImpl({
@JsonKey(name: 'id') this.id,
@JsonKey(name: 'organization_id') this.organizationId,
@JsonKey(name: 'name') this.name,
@JsonKey(name: 'description') this.description,
@JsonKey(name: 'business_type') this.businessType,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') this.createdAt,
@JsonKey(name: 'updated_at') this.updatedAt,
}) : _metadata = metadata,
super._();
factory _$CategoryDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$CategoryDtoImplFromJson(json);
@override
@JsonKey(name: 'id')
final String? id;
@override
@JsonKey(name: 'organization_id')
final String? organizationId;
@override
@JsonKey(name: 'name')
final String? name;
@override
@JsonKey(name: 'description')
final String? description;
@override
@JsonKey(name: 'business_type')
final String? businessType;
final Map<String, dynamic>? _metadata;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata {
final value = _metadata;
if (value == null) return null;
if (_metadata is EqualUnmodifiableMapView) return _metadata;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
@override
@JsonKey(name: 'created_at')
final DateTime? createdAt;
@override
@JsonKey(name: 'updated_at')
final DateTime? updatedAt;
@override
String toString() {
return 'CategoryDto(id: $id, organizationId: $organizationId, name: $name, description: $description, businessType: $businessType, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CategoryDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.organizationId, organizationId) ||
other.organizationId == organizationId) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.description, description) ||
other.description == description) &&
(identical(other.businessType, businessType) ||
other.businessType == businessType) &&
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
id,
organizationId,
name,
description,
businessType,
const DeepCollectionEquality().hash(_metadata),
createdAt,
updatedAt,
);
/// Create a copy of CategoryDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CategoryDtoImplCopyWith<_$CategoryDtoImpl> get copyWith =>
__$$CategoryDtoImplCopyWithImpl<_$CategoryDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$CategoryDtoImplToJson(this);
}
}
abstract class _CategoryDto extends CategoryDto {
const factory _CategoryDto({
@JsonKey(name: 'id') final String? id,
@JsonKey(name: 'organization_id') final String? organizationId,
@JsonKey(name: 'name') final String? name,
@JsonKey(name: 'description') final String? description,
@JsonKey(name: 'business_type') final String? businessType,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') final DateTime? createdAt,
@JsonKey(name: 'updated_at') final DateTime? updatedAt,
}) = _$CategoryDtoImpl;
const _CategoryDto._() : super._();
factory _CategoryDto.fromJson(Map<String, dynamic> json) =
_$CategoryDtoImpl.fromJson;
@override
@JsonKey(name: 'id')
String? get id;
@override
@JsonKey(name: 'organization_id')
String? get organizationId;
@override
@JsonKey(name: 'name')
String? get name;
@override
@JsonKey(name: 'description')
String? get description;
@override
@JsonKey(name: 'business_type')
String? get businessType;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata;
@override
@JsonKey(name: 'created_at')
DateTime? get createdAt;
@override
@JsonKey(name: 'updated_at')
DateTime? get updatedAt;
/// Create a copy of CategoryDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CategoryDtoImplCopyWith<_$CategoryDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,35 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'category_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$CategoryDtoImpl _$$CategoryDtoImplFromJson(Map<String, dynamic> json) =>
_$CategoryDtoImpl(
id: json['id'] as String?,
organizationId: json['organization_id'] as String?,
name: json['name'] as String?,
description: json['description'] as String?,
businessType: json['business_type'] as String?,
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
);
Map<String, dynamic> _$$CategoryDtoImplToJson(_$CategoryDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'organization_id': instance.organizationId,
'name': instance.name,
'description': instance.description,
'business_type': instance.businessType,
'metadata': instance.metadata,
'created_at': instance.createdAt?.toIso8601String(),
'updated_at': instance.updatedAt?.toIso8601String(),
};

View File

@ -1,46 +0,0 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/category/category.dart';
import '../category_dtos.dart';
@injectable
class CategoryRemoteDataProvider {
final ApiClient _apiClient;
final String _logName = 'CategoryRemoteDataProvider';
CategoryRemoteDataProvider(this._apiClient);
Future<DC<CategoryFailure, List<CategoryDto>>> fetch({
int page = 1,
int limit = 20,
bool isActive = true,
}) async {
try {
final response = await _apiClient.get(
ApiPath.category,
params: {'page': page, 'limit': limit, 'is_active': isActive},
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(CategoryFailure.empty());
}
final dto = (response.data['data']['categories'] as List)
.map((item) => CategoryDto.fromJson(item))
.toList();
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchCategoryError', name: _logName, error: e, stackTrace: s);
return DC.error(CategoryFailure.serverError(e));
}
}
}

View File

@ -1,31 +0,0 @@
part of '../category_dtos.dart';
@freezed
class CategoryDto with _$CategoryDto {
const CategoryDto._();
const factory CategoryDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'description') String? description,
@JsonKey(name: 'business_type') String? businessType,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
}) = _CategoryDto;
factory CategoryDto.fromJson(Map<String, dynamic> json) =>
_$CategoryDtoFromJson(json);
Category toDomain() => Category(
id: id ?? '',
organizationId: organizationId ?? '',
name: name ?? '',
description: description ?? '',
businessType: businessType ?? '',
metadata: metadata ?? {},
createdAt: createdAt,
updatedAt: updatedAt,
);
}

View File

@ -1,41 +0,0 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/category/category.dart';
import '../datasource/remote_data_provider.dart';
@Injectable(as: ICategoryRepository)
class CategoryRepository implements ICategoryRepository {
final CategoryRemoteDataProvider _dataProvider;
final String _logName = 'CategoryRepository';
CategoryRepository(this._dataProvider);
@override
Future<Either<CategoryFailure, List<Category>>> get({
int page = 1,
int limit = 20,
bool isActive = true,
}) async {
try {
final result = await _dataProvider.fetch(
page: page,
limit: limit,
isActive: isActive,
);
if (result.hasError) {
return left(result.error!);
}
final auth = result.data!.map((e) => e.toDomain()).toList();
return right(auth);
} catch (e, s) {
log('getCategoryError', name: _logName, error: e, stackTrace: s);
return left(const CategoryFailure.unexpectedError());
}
}
}

View File

@ -1,57 +0,0 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/product/product.dart';
import '../product_dtos.dart';
@injectable
class ProductRemoteDataProvider {
final ApiClient _apiClient;
final String _logName = 'ProductRemoteDataProvider';
ProductRemoteDataProvider(this._apiClient);
Future<DC<ProductFailure, List<ProductDto>>> fetch({
int page = 1,
int limit = 10,
String? categoryId,
String? search,
}) async {
try {
Map<String, dynamic> params = {'page': page, 'limit': limit};
if (categoryId != null) {
params['category_id'] = categoryId;
}
if (search != null) {
params['search'] = search;
}
final response = await _apiClient.get(
ApiPath.product,
params: params,
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(ProductFailure.empty());
}
final dto = (response.data['data']['products'] as List)
.map((item) => ProductDto.fromJson(item))
.toList();
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchProductError', name: _logName, error: e, stackTrace: s);
return DC.error(ProductFailure.serverError(e));
}
}
}

View File

@ -1,70 +0,0 @@
part of '../product_dtos.dart';
@freezed
class ProductDto with _$ProductDto {
const ProductDto._();
const factory ProductDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'category_id') String? categoryId,
@JsonKey(name: 'sku') String? sku,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'description') String? description,
@JsonKey(name: 'price') int? price,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'business_type') String? businessType,
@JsonKey(name: 'image_url') String? imageUrl,
@JsonKey(name: 'printer_type') String? printerType,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'is_active') bool? isActive,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
@JsonKey(name: 'variants') List<ProductVariantDto>? variants,
}) = _ProductDto;
factory ProductDto.fromJson(Map<String, dynamic> json) =>
_$ProductDtoFromJson(json);
/// DTO -> Domain (isi default kalau null)
Product toDomain() => Product(
id: id ?? '',
organizationId: organizationId ?? '',
categoryId: categoryId ?? '',
sku: sku ?? '',
name: name ?? '',
description: description ?? '',
price: price ?? 0,
cost: cost ?? 0,
businessType: businessType ?? '',
imageUrl: imageUrl ?? '',
printerType: printerType ?? '',
metadata: metadata ?? {},
isActive: isActive ?? false,
createdAt: createdAt ?? DateTime.now(),
updatedAt: updatedAt ?? DateTime.now(),
variants: variants?.map((v) => v.toDomain()).toList() ?? [],
);
/// Domain -> DTO
factory ProductDto.fromDomain(Product product) => ProductDto(
id: product.id,
organizationId: product.organizationId,
categoryId: product.categoryId,
sku: product.sku,
name: product.name,
description: product.description,
price: product.price,
cost: product.cost,
businessType: product.businessType,
imageUrl: product.imageUrl,
printerType: product.printerType,
metadata: product.metadata,
isActive: product.isActive,
createdAt: product.createdAt,
updatedAt: product.updatedAt,
variants: product.variants
.map((v) => ProductVariantDto.fromDomain(v))
.toList(),
);
}

View File

@ -1,45 +0,0 @@
part of '../product_dtos.dart';
@freezed
class ProductVariantDto with _$ProductVariantDto {
const ProductVariantDto._();
const factory ProductVariantDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'product_id') String? productId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'price_modifier') int? priceModifier,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
}) = _ProductVariantDto;
factory ProductVariantDto.fromJson(Map<String, dynamic> json) =>
_$ProductVariantDtoFromJson(json);
/// DTO -> Domain
ProductVariant toDomain() => ProductVariant(
id: id ?? '',
productId: productId ?? '',
name: name ?? '',
priceModifier: priceModifier ?? 0,
cost: cost ?? 0,
metadata: metadata ?? {},
createdAt: createdAt ?? DateTime.now(),
updatedAt: updatedAt ?? DateTime.now(),
);
/// Domain -> DTO
factory ProductVariantDto.fromDomain(ProductVariant variant) =>
ProductVariantDto(
id: variant.id,
productId: variant.productId,
name: variant.name,
priceModifier: variant.priceModifier,
cost: variant.cost,
metadata: variant.metadata,
createdAt: variant.createdAt,
updatedAt: variant.updatedAt,
);
}

View File

@ -1,9 +0,0 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/product/product.dart';
part 'product_dtos.freezed.dart';
part 'product_dtos.g.dart';
part 'dto/product_dto.dart';
part 'dto/product_variant_dto.dart';

View File

@ -1,926 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'product_dtos.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
ProductDto _$ProductDtoFromJson(Map<String, dynamic> json) {
return _ProductDto.fromJson(json);
}
/// @nodoc
mixin _$ProductDto {
@JsonKey(name: 'id')
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: 'organization_id')
String? get organizationId => throw _privateConstructorUsedError;
@JsonKey(name: 'category_id')
String? get categoryId => throw _privateConstructorUsedError;
@JsonKey(name: 'sku')
String? get sku => throw _privateConstructorUsedError;
@JsonKey(name: 'name')
String? get name => throw _privateConstructorUsedError;
@JsonKey(name: 'description')
String? get description => throw _privateConstructorUsedError;
@JsonKey(name: 'price')
int? get price => throw _privateConstructorUsedError;
@JsonKey(name: 'cost')
int? get cost => throw _privateConstructorUsedError;
@JsonKey(name: 'business_type')
String? get businessType => throw _privateConstructorUsedError;
@JsonKey(name: 'image_url')
String? get imageUrl => throw _privateConstructorUsedError;
@JsonKey(name: 'printer_type')
String? get printerType => throw _privateConstructorUsedError;
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
@JsonKey(name: 'is_active')
bool? get isActive => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
DateTime? get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: 'updated_at')
DateTime? get updatedAt => throw _privateConstructorUsedError;
@JsonKey(name: 'variants')
List<ProductVariantDto>? get variants => throw _privateConstructorUsedError;
/// Serializes this ProductDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of ProductDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ProductDtoCopyWith<ProductDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProductDtoCopyWith<$Res> {
factory $ProductDtoCopyWith(
ProductDto value,
$Res Function(ProductDto) then,
) = _$ProductDtoCopyWithImpl<$Res, ProductDto>;
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'category_id') String? categoryId,
@JsonKey(name: 'sku') String? sku,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'description') String? description,
@JsonKey(name: 'price') int? price,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'business_type') String? businessType,
@JsonKey(name: 'image_url') String? imageUrl,
@JsonKey(name: 'printer_type') String? printerType,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'is_active') bool? isActive,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
@JsonKey(name: 'variants') List<ProductVariantDto>? variants,
});
}
/// @nodoc
class _$ProductDtoCopyWithImpl<$Res, $Val extends ProductDto>
implements $ProductDtoCopyWith<$Res> {
_$ProductDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProductDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? organizationId = freezed,
Object? categoryId = freezed,
Object? sku = freezed,
Object? name = freezed,
Object? description = freezed,
Object? price = freezed,
Object? cost = freezed,
Object? businessType = freezed,
Object? imageUrl = freezed,
Object? printerType = freezed,
Object? metadata = freezed,
Object? isActive = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
Object? variants = freezed,
}) {
return _then(
_value.copyWith(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
organizationId: freezed == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String?,
categoryId: freezed == categoryId
? _value.categoryId
: categoryId // ignore: cast_nullable_to_non_nullable
as String?,
sku: freezed == sku
? _value.sku
: sku // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
description: freezed == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String?,
price: freezed == price
? _value.price
: price // ignore: cast_nullable_to_non_nullable
as int?,
cost: freezed == cost
? _value.cost
: cost // ignore: cast_nullable_to_non_nullable
as int?,
businessType: freezed == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String?,
imageUrl: freezed == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String?,
printerType: freezed == printerType
? _value.printerType
: printerType // ignore: cast_nullable_to_non_nullable
as String?,
metadata: freezed == metadata
? _value.metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
isActive: freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
variants: freezed == variants
? _value.variants
: variants // ignore: cast_nullable_to_non_nullable
as List<ProductVariantDto>?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$ProductDtoImplCopyWith<$Res>
implements $ProductDtoCopyWith<$Res> {
factory _$$ProductDtoImplCopyWith(
_$ProductDtoImpl value,
$Res Function(_$ProductDtoImpl) then,
) = __$$ProductDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'category_id') String? categoryId,
@JsonKey(name: 'sku') String? sku,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'description') String? description,
@JsonKey(name: 'price') int? price,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'business_type') String? businessType,
@JsonKey(name: 'image_url') String? imageUrl,
@JsonKey(name: 'printer_type') String? printerType,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'is_active') bool? isActive,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
@JsonKey(name: 'variants') List<ProductVariantDto>? variants,
});
}
/// @nodoc
class __$$ProductDtoImplCopyWithImpl<$Res>
extends _$ProductDtoCopyWithImpl<$Res, _$ProductDtoImpl>
implements _$$ProductDtoImplCopyWith<$Res> {
__$$ProductDtoImplCopyWithImpl(
_$ProductDtoImpl _value,
$Res Function(_$ProductDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of ProductDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? organizationId = freezed,
Object? categoryId = freezed,
Object? sku = freezed,
Object? name = freezed,
Object? description = freezed,
Object? price = freezed,
Object? cost = freezed,
Object? businessType = freezed,
Object? imageUrl = freezed,
Object? printerType = freezed,
Object? metadata = freezed,
Object? isActive = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
Object? variants = freezed,
}) {
return _then(
_$ProductDtoImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
organizationId: freezed == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String?,
categoryId: freezed == categoryId
? _value.categoryId
: categoryId // ignore: cast_nullable_to_non_nullable
as String?,
sku: freezed == sku
? _value.sku
: sku // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
description: freezed == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String?,
price: freezed == price
? _value.price
: price // ignore: cast_nullable_to_non_nullable
as int?,
cost: freezed == cost
? _value.cost
: cost // ignore: cast_nullable_to_non_nullable
as int?,
businessType: freezed == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String?,
imageUrl: freezed == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String?,
printerType: freezed == printerType
? _value.printerType
: printerType // ignore: cast_nullable_to_non_nullable
as String?,
metadata: freezed == metadata
? _value._metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
isActive: freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
variants: freezed == variants
? _value._variants
: variants // ignore: cast_nullable_to_non_nullable
as List<ProductVariantDto>?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$ProductDtoImpl extends _ProductDto {
const _$ProductDtoImpl({
@JsonKey(name: 'id') this.id,
@JsonKey(name: 'organization_id') this.organizationId,
@JsonKey(name: 'category_id') this.categoryId,
@JsonKey(name: 'sku') this.sku,
@JsonKey(name: 'name') this.name,
@JsonKey(name: 'description') this.description,
@JsonKey(name: 'price') this.price,
@JsonKey(name: 'cost') this.cost,
@JsonKey(name: 'business_type') this.businessType,
@JsonKey(name: 'image_url') this.imageUrl,
@JsonKey(name: 'printer_type') this.printerType,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'is_active') this.isActive,
@JsonKey(name: 'created_at') this.createdAt,
@JsonKey(name: 'updated_at') this.updatedAt,
@JsonKey(name: 'variants') final List<ProductVariantDto>? variants,
}) : _metadata = metadata,
_variants = variants,
super._();
factory _$ProductDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$ProductDtoImplFromJson(json);
@override
@JsonKey(name: 'id')
final String? id;
@override
@JsonKey(name: 'organization_id')
final String? organizationId;
@override
@JsonKey(name: 'category_id')
final String? categoryId;
@override
@JsonKey(name: 'sku')
final String? sku;
@override
@JsonKey(name: 'name')
final String? name;
@override
@JsonKey(name: 'description')
final String? description;
@override
@JsonKey(name: 'price')
final int? price;
@override
@JsonKey(name: 'cost')
final int? cost;
@override
@JsonKey(name: 'business_type')
final String? businessType;
@override
@JsonKey(name: 'image_url')
final String? imageUrl;
@override
@JsonKey(name: 'printer_type')
final String? printerType;
final Map<String, dynamic>? _metadata;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata {
final value = _metadata;
if (value == null) return null;
if (_metadata is EqualUnmodifiableMapView) return _metadata;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
@override
@JsonKey(name: 'is_active')
final bool? isActive;
@override
@JsonKey(name: 'created_at')
final DateTime? createdAt;
@override
@JsonKey(name: 'updated_at')
final DateTime? updatedAt;
final List<ProductVariantDto>? _variants;
@override
@JsonKey(name: 'variants')
List<ProductVariantDto>? get variants {
final value = _variants;
if (value == null) return null;
if (_variants is EqualUnmodifiableListView) return _variants;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override
String toString() {
return 'ProductDto(id: $id, organizationId: $organizationId, categoryId: $categoryId, sku: $sku, name: $name, description: $description, price: $price, cost: $cost, businessType: $businessType, imageUrl: $imageUrl, printerType: $printerType, metadata: $metadata, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt, variants: $variants)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProductDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.organizationId, organizationId) ||
other.organizationId == organizationId) &&
(identical(other.categoryId, categoryId) ||
other.categoryId == categoryId) &&
(identical(other.sku, sku) || other.sku == sku) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.description, description) ||
other.description == description) &&
(identical(other.price, price) || other.price == price) &&
(identical(other.cost, cost) || other.cost == cost) &&
(identical(other.businessType, businessType) ||
other.businessType == businessType) &&
(identical(other.imageUrl, imageUrl) ||
other.imageUrl == imageUrl) &&
(identical(other.printerType, printerType) ||
other.printerType == printerType) &&
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
(identical(other.isActive, isActive) ||
other.isActive == isActive) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt) &&
const DeepCollectionEquality().equals(other._variants, _variants));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
id,
organizationId,
categoryId,
sku,
name,
description,
price,
cost,
businessType,
imageUrl,
printerType,
const DeepCollectionEquality().hash(_metadata),
isActive,
createdAt,
updatedAt,
const DeepCollectionEquality().hash(_variants),
);
/// Create a copy of ProductDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ProductDtoImplCopyWith<_$ProductDtoImpl> get copyWith =>
__$$ProductDtoImplCopyWithImpl<_$ProductDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ProductDtoImplToJson(this);
}
}
abstract class _ProductDto extends ProductDto {
const factory _ProductDto({
@JsonKey(name: 'id') final String? id,
@JsonKey(name: 'organization_id') final String? organizationId,
@JsonKey(name: 'category_id') final String? categoryId,
@JsonKey(name: 'sku') final String? sku,
@JsonKey(name: 'name') final String? name,
@JsonKey(name: 'description') final String? description,
@JsonKey(name: 'price') final int? price,
@JsonKey(name: 'cost') final int? cost,
@JsonKey(name: 'business_type') final String? businessType,
@JsonKey(name: 'image_url') final String? imageUrl,
@JsonKey(name: 'printer_type') final String? printerType,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'is_active') final bool? isActive,
@JsonKey(name: 'created_at') final DateTime? createdAt,
@JsonKey(name: 'updated_at') final DateTime? updatedAt,
@JsonKey(name: 'variants') final List<ProductVariantDto>? variants,
}) = _$ProductDtoImpl;
const _ProductDto._() : super._();
factory _ProductDto.fromJson(Map<String, dynamic> json) =
_$ProductDtoImpl.fromJson;
@override
@JsonKey(name: 'id')
String? get id;
@override
@JsonKey(name: 'organization_id')
String? get organizationId;
@override
@JsonKey(name: 'category_id')
String? get categoryId;
@override
@JsonKey(name: 'sku')
String? get sku;
@override
@JsonKey(name: 'name')
String? get name;
@override
@JsonKey(name: 'description')
String? get description;
@override
@JsonKey(name: 'price')
int? get price;
@override
@JsonKey(name: 'cost')
int? get cost;
@override
@JsonKey(name: 'business_type')
String? get businessType;
@override
@JsonKey(name: 'image_url')
String? get imageUrl;
@override
@JsonKey(name: 'printer_type')
String? get printerType;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata;
@override
@JsonKey(name: 'is_active')
bool? get isActive;
@override
@JsonKey(name: 'created_at')
DateTime? get createdAt;
@override
@JsonKey(name: 'updated_at')
DateTime? get updatedAt;
@override
@JsonKey(name: 'variants')
List<ProductVariantDto>? get variants;
/// Create a copy of ProductDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ProductDtoImplCopyWith<_$ProductDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}
ProductVariantDto _$ProductVariantDtoFromJson(Map<String, dynamic> json) {
return _ProductVariantDto.fromJson(json);
}
/// @nodoc
mixin _$ProductVariantDto {
@JsonKey(name: 'id')
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: 'product_id')
String? get productId => throw _privateConstructorUsedError;
@JsonKey(name: 'name')
String? get name => throw _privateConstructorUsedError;
@JsonKey(name: 'price_modifier')
int? get priceModifier => throw _privateConstructorUsedError;
@JsonKey(name: 'cost')
int? get cost => throw _privateConstructorUsedError;
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
DateTime? get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: 'updated_at')
DateTime? get updatedAt => throw _privateConstructorUsedError;
/// Serializes this ProductVariantDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of ProductVariantDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ProductVariantDtoCopyWith<ProductVariantDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProductVariantDtoCopyWith<$Res> {
factory $ProductVariantDtoCopyWith(
ProductVariantDto value,
$Res Function(ProductVariantDto) then,
) = _$ProductVariantDtoCopyWithImpl<$Res, ProductVariantDto>;
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'product_id') String? productId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'price_modifier') int? priceModifier,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
});
}
/// @nodoc
class _$ProductVariantDtoCopyWithImpl<$Res, $Val extends ProductVariantDto>
implements $ProductVariantDtoCopyWith<$Res> {
_$ProductVariantDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProductVariantDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? productId = freezed,
Object? name = freezed,
Object? priceModifier = freezed,
Object? cost = freezed,
Object? metadata = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_value.copyWith(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
productId: freezed == productId
? _value.productId
: productId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
priceModifier: freezed == priceModifier
? _value.priceModifier
: priceModifier // ignore: cast_nullable_to_non_nullable
as int?,
cost: freezed == cost
? _value.cost
: cost // ignore: cast_nullable_to_non_nullable
as int?,
metadata: freezed == metadata
? _value.metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$ProductVariantDtoImplCopyWith<$Res>
implements $ProductVariantDtoCopyWith<$Res> {
factory _$$ProductVariantDtoImplCopyWith(
_$ProductVariantDtoImpl value,
$Res Function(_$ProductVariantDtoImpl) then,
) = __$$ProductVariantDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'product_id') String? productId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'price_modifier') int? priceModifier,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') DateTime? createdAt,
@JsonKey(name: 'updated_at') DateTime? updatedAt,
});
}
/// @nodoc
class __$$ProductVariantDtoImplCopyWithImpl<$Res>
extends _$ProductVariantDtoCopyWithImpl<$Res, _$ProductVariantDtoImpl>
implements _$$ProductVariantDtoImplCopyWith<$Res> {
__$$ProductVariantDtoImplCopyWithImpl(
_$ProductVariantDtoImpl _value,
$Res Function(_$ProductVariantDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of ProductVariantDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? productId = freezed,
Object? name = freezed,
Object? priceModifier = freezed,
Object? cost = freezed,
Object? metadata = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$ProductVariantDtoImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
productId: freezed == productId
? _value.productId
: productId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
priceModifier: freezed == priceModifier
? _value.priceModifier
: priceModifier // ignore: cast_nullable_to_non_nullable
as int?,
cost: freezed == cost
? _value.cost
: cost // ignore: cast_nullable_to_non_nullable
as int?,
metadata: freezed == metadata
? _value._metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$ProductVariantDtoImpl extends _ProductVariantDto {
const _$ProductVariantDtoImpl({
@JsonKey(name: 'id') this.id,
@JsonKey(name: 'product_id') this.productId,
@JsonKey(name: 'name') this.name,
@JsonKey(name: 'price_modifier') this.priceModifier,
@JsonKey(name: 'cost') this.cost,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') this.createdAt,
@JsonKey(name: 'updated_at') this.updatedAt,
}) : _metadata = metadata,
super._();
factory _$ProductVariantDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$ProductVariantDtoImplFromJson(json);
@override
@JsonKey(name: 'id')
final String? id;
@override
@JsonKey(name: 'product_id')
final String? productId;
@override
@JsonKey(name: 'name')
final String? name;
@override
@JsonKey(name: 'price_modifier')
final int? priceModifier;
@override
@JsonKey(name: 'cost')
final int? cost;
final Map<String, dynamic>? _metadata;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata {
final value = _metadata;
if (value == null) return null;
if (_metadata is EqualUnmodifiableMapView) return _metadata;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
@override
@JsonKey(name: 'created_at')
final DateTime? createdAt;
@override
@JsonKey(name: 'updated_at')
final DateTime? updatedAt;
@override
String toString() {
return 'ProductVariantDto(id: $id, productId: $productId, name: $name, priceModifier: $priceModifier, cost: $cost, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProductVariantDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.productId, productId) ||
other.productId == productId) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.priceModifier, priceModifier) ||
other.priceModifier == priceModifier) &&
(identical(other.cost, cost) || other.cost == cost) &&
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
id,
productId,
name,
priceModifier,
cost,
const DeepCollectionEquality().hash(_metadata),
createdAt,
updatedAt,
);
/// Create a copy of ProductVariantDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ProductVariantDtoImplCopyWith<_$ProductVariantDtoImpl> get copyWith =>
__$$ProductVariantDtoImplCopyWithImpl<_$ProductVariantDtoImpl>(
this,
_$identity,
);
@override
Map<String, dynamic> toJson() {
return _$$ProductVariantDtoImplToJson(this);
}
}
abstract class _ProductVariantDto extends ProductVariantDto {
const factory _ProductVariantDto({
@JsonKey(name: 'id') final String? id,
@JsonKey(name: 'product_id') final String? productId,
@JsonKey(name: 'name') final String? name,
@JsonKey(name: 'price_modifier') final int? priceModifier,
@JsonKey(name: 'cost') final int? cost,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') final DateTime? createdAt,
@JsonKey(name: 'updated_at') final DateTime? updatedAt,
}) = _$ProductVariantDtoImpl;
const _ProductVariantDto._() : super._();
factory _ProductVariantDto.fromJson(Map<String, dynamic> json) =
_$ProductVariantDtoImpl.fromJson;
@override
@JsonKey(name: 'id')
String? get id;
@override
@JsonKey(name: 'product_id')
String? get productId;
@override
@JsonKey(name: 'name')
String? get name;
@override
@JsonKey(name: 'price_modifier')
int? get priceModifier;
@override
@JsonKey(name: 'cost')
int? get cost;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata;
@override
@JsonKey(name: 'created_at')
DateTime? get createdAt;
@override
@JsonKey(name: 'updated_at')
DateTime? get updatedAt;
/// Create a copy of ProductVariantDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ProductVariantDtoImplCopyWith<_$ProductVariantDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,83 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'product_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ProductDtoImpl _$$ProductDtoImplFromJson(Map<String, dynamic> json) =>
_$ProductDtoImpl(
id: json['id'] as String?,
organizationId: json['organization_id'] as String?,
categoryId: json['category_id'] as String?,
sku: json['sku'] as String?,
name: json['name'] as String?,
description: json['description'] as String?,
price: (json['price'] as num?)?.toInt(),
cost: (json['cost'] as num?)?.toInt(),
businessType: json['business_type'] as String?,
imageUrl: json['image_url'] as String?,
printerType: json['printer_type'] as String?,
metadata: json['metadata'] as Map<String, dynamic>?,
isActive: json['is_active'] as bool?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
variants: (json['variants'] as List<dynamic>?)
?.map((e) => ProductVariantDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$ProductDtoImplToJson(_$ProductDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'organization_id': instance.organizationId,
'category_id': instance.categoryId,
'sku': instance.sku,
'name': instance.name,
'description': instance.description,
'price': instance.price,
'cost': instance.cost,
'business_type': instance.businessType,
'image_url': instance.imageUrl,
'printer_type': instance.printerType,
'metadata': instance.metadata,
'is_active': instance.isActive,
'created_at': instance.createdAt?.toIso8601String(),
'updated_at': instance.updatedAt?.toIso8601String(),
'variants': instance.variants,
};
_$ProductVariantDtoImpl _$$ProductVariantDtoImplFromJson(
Map<String, dynamic> json,
) => _$ProductVariantDtoImpl(
id: json['id'] as String?,
productId: json['product_id'] as String?,
name: json['name'] as String?,
priceModifier: (json['price_modifier'] as num?)?.toInt(),
cost: (json['cost'] as num?)?.toInt(),
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
);
Map<String, dynamic> _$$ProductVariantDtoImplToJson(
_$ProductVariantDtoImpl instance,
) => <String, dynamic>{
'id': instance.id,
'product_id': instance.productId,
'name': instance.name,
'price_modifier': instance.priceModifier,
'cost': instance.cost,
'metadata': instance.metadata,
'created_at': instance.createdAt?.toIso8601String(),
'updated_at': instance.updatedAt?.toIso8601String(),
};

View File

@ -1,43 +0,0 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/product/product.dart';
import '../datasources/remote_data_provider.dart';
@Injectable(as: IProductRepository)
class ProductRepository implements IProductRepository {
final ProductRemoteDataProvider _dataProvider;
final String _logName = 'ProductRepository';
ProductRepository(this._dataProvider);
@override
Future<Either<ProductFailure, List<Product>>> get({
int page = 1,
int limit = 10,
String? categoryId,
String? search,
}) async {
try {
final result = await _dataProvider.fetch(
page: page,
limit: limit,
categoryId: categoryId,
search: search,
);
if (result.hasError) {
return left(result.error!);
}
final auth = result.data!.map((e) => e.toDomain()).toList();
return right(auth);
} catch (e, s) {
log('getProductError', name: _logName, error: e, stackTrace: s);
return left(const ProductFailure.unexpectedError());
}
}
}

View File

@ -9,23 +9,13 @@
// coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:apskel_owner_flutter/application/analytic/category_analytic_loader/category_analytic_loader_bloc.dart'
as _i1038;
import 'package:apskel_owner_flutter/application/analytic/profit_loss_loader/profit_loss_loader_bloc.dart'
as _i11;
import 'package:apskel_owner_flutter/application/analytic/sales_loader/sales_loader_bloc.dart'
as _i889;
import 'package:apskel_owner_flutter/application/auth/auth_bloc.dart' as _i945;
import 'package:apskel_owner_flutter/application/auth/login_form/login_form_bloc.dart'
as _i775;
import 'package:apskel_owner_flutter/application/auth/logout_form/logout_form_bloc.dart'
as _i574;
import 'package:apskel_owner_flutter/application/category/category_loader/category_loader_bloc.dart'
as _i183;
import 'package:apskel_owner_flutter/application/language/language_bloc.dart'
as _i455;
import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart'
as _i458;
import 'package:apskel_owner_flutter/common/api/api_client.dart' as _i115;
import 'package:apskel_owner_flutter/common/di/di_auto_route.dart' as _i311;
import 'package:apskel_owner_flutter/common/di/di_connectivity.dart' as _i586;
@ -35,30 +25,14 @@ import 'package:apskel_owner_flutter/common/di/di_shared_preferences.dart'
as _i402;
import 'package:apskel_owner_flutter/common/network/network_client.dart'
as _i543;
import 'package:apskel_owner_flutter/domain/analytic/repositories/i_analytic_repository.dart'
as _i477;
import 'package:apskel_owner_flutter/domain/auth/auth.dart' as _i49;
import 'package:apskel_owner_flutter/domain/category/category.dart' as _i1020;
import 'package:apskel_owner_flutter/domain/product/product.dart' as _i419;
import 'package:apskel_owner_flutter/env.dart' as _i6;
import 'package:apskel_owner_flutter/infrastructure/analytic/datasource/remote_data_provider.dart'
as _i866;
import 'package:apskel_owner_flutter/infrastructure/analytic/repositories/analytic_repository.dart'
as _i393;
import 'package:apskel_owner_flutter/infrastructure/auth/datasources/local_data_provider.dart'
as _i991;
import 'package:apskel_owner_flutter/infrastructure/auth/datasources/remote_data_provider.dart'
as _i17;
import 'package:apskel_owner_flutter/infrastructure/auth/repositories/auth_repository.dart'
as _i1035;
import 'package:apskel_owner_flutter/infrastructure/category/datasource/remote_data_provider.dart'
as _i333;
import 'package:apskel_owner_flutter/infrastructure/category/repositories/category_repository.dart'
as _i869;
import 'package:apskel_owner_flutter/infrastructure/product/datasources/remote_data_provider.dart'
as _i823;
import 'package:apskel_owner_flutter/infrastructure/product/repositories/product_repository.dart'
as _i121;
import 'package:apskel_owner_flutter/presentation/router/app_router.dart'
as _i258;
import 'package:connectivity_plus/connectivity_plus.dart' as _i895;
@ -104,52 +78,23 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i991.AuthLocalDataProvider>(
() => _i991.AuthLocalDataProvider(gh<_i460.SharedPreferences>()),
);
gh.lazySingleton<_i115.ApiClient>(
() => _i115.ApiClient(gh<_i361.Dio>(), gh<_i6.Env>()),
);
gh.factory<_i6.Env>(() => _i6.ProdEnv(), registerFor: {_prod});
gh.factory<_i333.CategoryRemoteDataProvider>(
() => _i333.CategoryRemoteDataProvider(gh<_i115.ApiClient>()),
gh.lazySingleton<_i115.ApiClient>(
() => _i115.ApiClient(
gh<_i361.Dio>(),
gh<_i6.Env>(),
gh<_i460.SharedPreferences>(),
),
);
gh.factory<_i17.AuthRemoteDataProvider>(
() => _i17.AuthRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i823.ProductRemoteDataProvider>(
() => _i823.ProductRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i866.AnalyticRemoteDataProvider>(
() => _i866.AnalyticRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i477.IAnalyticRepository>(
() => _i393.AnalyticRepository(gh<_i866.AnalyticRemoteDataProvider>()),
);
gh.factory<_i49.IAuthRepository>(
() => _i1035.AuthRepository(
gh<_i991.AuthLocalDataProvider>(),
gh<_i17.AuthRemoteDataProvider>(),
),
);
gh.factory<_i419.IProductRepository>(
() => _i121.ProductRepository(gh<_i823.ProductRemoteDataProvider>()),
);
gh.factory<_i1020.ICategoryRepository>(
() => _i869.CategoryRepository(gh<_i333.CategoryRemoteDataProvider>()),
);
gh.factory<_i458.ProductLoaderBloc>(
() => _i458.ProductLoaderBloc(gh<_i419.IProductRepository>()),
);
gh.factory<_i183.CategoryLoaderBloc>(
() => _i183.CategoryLoaderBloc(gh<_i1020.ICategoryRepository>()),
);
gh.factory<_i889.SalesLoaderBloc>(
() => _i889.SalesLoaderBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i11.ProfitLossLoaderBloc>(
() => _i11.ProfitLossLoaderBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i1038.CategoryAnalyticLoaderBloc>(
() => _i1038.CategoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i775.LoginFormBloc>(
() => _i775.LoginFormBloc(gh<_i49.IAuthRepository>()),
);

View File

@ -1,5 +0,0 @@
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:shimmer/shimmer.dart';
part 'network_image.dart';

View File

@ -1,68 +0,0 @@
part of 'image.dart';
class AppNetworkImage extends StatelessWidget {
final String? url;
final double? height;
final double? width;
final double? borderRadius;
final BoxFit? fit;
final bool? isCanZoom;
final VoidCallback? onTap;
const AppNetworkImage({
super.key,
this.url,
this.height,
this.width,
this.borderRadius = 0,
this.fit = BoxFit.cover,
this.isCanZoom = false,
this.onTap,
});
@override
Widget build(BuildContext context) {
Widget customPhoto(
double? heightx,
double? widthx,
BoxFit? fitx,
double? radius,
) {
return CachedNetworkImage(
imageUrl: url.toString(),
placeholder: (context, url) => Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Container(
height: height,
width: width,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(radius ?? 0),
),
),
),
errorWidget: (context, url, error) => Container(
height: height,
width: width,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(radius ?? 0),
),
child: Icon(Icons.image_outlined, color: Colors.grey.shade400),
),
height: heightx,
width: widthx,
fit: fitx,
);
}
return GestureDetector(
onTap: onTap,
child: ClipRRect(
borderRadius: BorderRadius.circular(borderRadius!),
child: customPhoto(height, width, BoxFit.fill, borderRadius),
),
);
}
}

View File

@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
import 'empty_widget.dart';
class EmptySearchWidget extends StatelessWidget {
final String? searchQuery;
final VoidCallback? onClear;
const EmptySearchWidget({Key? key, this.searchQuery, this.onClear})
: super(key: key);
@override
Widget build(BuildContext context) {
return EmptyWidget(
title: 'Pencarian Tidak Ditemukan',
message: searchQuery != null
? 'Tidak ada hasil untuk "$searchQuery"\nCoba kata kunci lain'
: 'Coba gunakan kata kunci yang berbeda',
emptyIcon: Icons.search_off_rounded,
iconColor: AppColor.warning,
buttonText: 'Hapus Filter',
onRefresh: onClear,
showButton: onClear != null,
);
}
}

View File

@ -1,179 +0,0 @@
// ==================== EMPTY WIDGET ====================
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
class EmptyWidget extends StatefulWidget {
final String? title;
final String? message;
final VoidCallback? onRefresh;
final IconData? emptyIcon;
final String? buttonText;
final double? width;
final double? height;
final bool showButton;
final EdgeInsets? padding;
final Color? iconColor;
const EmptyWidget({
super.key,
this.title,
this.message,
this.onRefresh,
this.emptyIcon,
this.buttonText,
this.width,
this.height,
this.showButton = true,
this.padding,
this.iconColor,
});
@override
State<EmptyWidget> createState() => _EmptyWidgetState();
}
class _EmptyWidgetState extends State<EmptyWidget>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0.0, 0.3), end: Offset.zero).animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.easeOutCubic,
),
);
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.width,
height: widget.height,
padding: widget.padding ?? const EdgeInsets.all(24),
child: FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
// Empty Illustration
Stack(
alignment: Alignment.center,
children: [
// Background Circle
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [
AppColor.primary.withOpacity(0.05),
AppColor.secondary.withOpacity(0.05),
],
),
),
),
// Icon Container
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.surface,
border: Border.all(color: AppColor.border, width: 2),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.08),
blurRadius: 20,
offset: const Offset(0, 4),
),
],
),
child: Icon(
widget.emptyIcon ?? Icons.inbox_outlined,
size: 40,
color: widget.iconColor ?? AppColor.textLight,
),
),
],
),
const SizedBox(height: 24),
// Title
Text(
widget.title ?? 'Tidak Ada Data',
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
// Message
Text(
widget.message ?? 'Belum ada data untuk ditampilkan',
style: AppStyle.md.copyWith(
color: AppColor.textSecondary,
height: 1.4,
),
textAlign: TextAlign.center,
),
// Action Button
if (widget.showButton && widget.onRefresh != null) ...[
const SizedBox(height: 24),
OutlinedButton.icon(
onPressed: widget.onRefresh,
icon: const Icon(Icons.refresh_rounded, size: 18),
label: Text(widget.buttonText ?? 'Muat Ulang'),
style: OutlinedButton.styleFrom(
foregroundColor: AppColor.primary,
side: BorderSide(color: AppColor.primary, width: 1.5),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
],
],
),
),
),
);
}
}

View File

@ -1,176 +0,0 @@
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
class ErrorWidget extends StatefulWidget {
final String? title;
final String? message;
final VoidCallback? onRetry;
final String? errorCode;
final IconData? errorIcon;
final double? width;
final double? height;
final bool showRetryButton;
final EdgeInsets? padding;
const ErrorWidget({
super.key,
this.title,
this.message,
this.onRetry,
this.errorCode,
this.errorIcon,
this.width,
this.height,
this.showRetryButton = true,
this.padding,
});
@override
State<ErrorWidget> createState() => _ErrorWidgetState();
}
class _ErrorWidgetState extends State<ErrorWidget>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 600),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
_scaleAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.elasticOut),
);
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.width,
height: widget.height,
padding: widget.padding ?? const EdgeInsets.all(24),
child: FadeTransition(
opacity: _fadeAnimation,
child: ScaleTransition(
scale: _scaleAnimation,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
// Error Icon
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [
AppColor.error.withOpacity(0.1),
AppColor.warning.withOpacity(0.1),
],
),
border: Border.all(
color: AppColor.error.withOpacity(0.2),
width: 2,
),
),
child: Icon(
widget.errorIcon ?? Icons.error_outline_rounded,
size: 40,
color: AppColor.error,
),
),
const SizedBox(height: 16),
// Title
if (widget.title != null)
Text(
widget.title!,
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
// Message
Text(
widget.message ?? 'Terjadi kesalahan tidak terduga',
style: AppStyle.md.copyWith(
color: AppColor.textSecondary,
height: 1.4,
),
textAlign: TextAlign.center,
),
// Error Code
if (widget.errorCode != null) ...[
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: AppColor.error.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.error.withOpacity(0.2)),
),
child: Text(
'Error: ${widget.errorCode}',
style: AppStyle.xs.copyWith(
color: AppColor.error,
fontWeight: FontWeight.w500,
),
),
),
],
// Retry Button
if (widget.showRetryButton && widget.onRetry != null) ...[
const SizedBox(height: 20),
ElevatedButton.icon(
onPressed: widget.onRetry,
icon: const Icon(Icons.refresh_rounded, size: 18),
label: const Text('Coba Lagi'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.primary,
foregroundColor: AppColor.textWhite,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
],
],
),
),
),
);
}
}

View File

@ -1,509 +0,0 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
@RoutePage()
class ErrorPage extends StatefulWidget {
final String? title;
final String? message;
final VoidCallback? onRetry;
final VoidCallback? onBack;
final String? errorCode;
final IconData? errorIcon;
const ErrorPage({
Key? key,
this.title,
this.message,
this.onRetry,
this.onBack,
this.errorCode,
this.errorIcon,
}) : super(key: key);
@override
State<ErrorPage> createState() => _ErrorPageState();
}
class _ErrorPageState extends State<ErrorPage> with TickerProviderStateMixin {
late AnimationController _bounceController;
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _bounceAnimation;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_bounceController = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: this,
);
_fadeController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_slideController = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
_bounceAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _bounceController, curve: Curves.elasticOut),
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0.0, 0.5), end: Offset.zero).animate(
CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic),
);
// Start animations
_bounceController.forward();
Future.delayed(const Duration(milliseconds: 300), () {
_fadeController.forward();
});
Future.delayed(const Duration(milliseconds: 500), () {
_slideController.forward();
});
}
@override
void dispose() {
_bounceController.dispose();
_fadeController.dispose();
_slideController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColor.primary.withOpacity(0.05),
AppColor.background,
AppColor.primaryLight.withOpacity(0.03),
],
),
),
child: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 60),
// Animated Error Illustration
AnimatedBuilder(
animation: _bounceAnimation,
builder: (context, child) {
return Transform.scale(
scale: _bounceAnimation.value,
child: Stack(
alignment: Alignment.center,
children: [
// Outer glow circle
Container(
width: 200,
height: 200,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
AppColor.error.withOpacity(0.1),
Colors.transparent,
],
),
),
),
// Middle circle with gradient
Container(
width: 140,
height: 140,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColor.error.withOpacity(0.15),
AppColor.warning.withOpacity(0.15),
AppColor.primary.withOpacity(0.1),
],
),
boxShadow: [
BoxShadow(
color: AppColor.error.withOpacity(0.2),
blurRadius: 30,
offset: const Offset(0, 10),
),
],
),
),
// Inner circle with icon
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: AppColor.primaryGradient,
),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
),
child: Icon(
widget.errorIcon ?? Icons.sentiment_dissatisfied,
size: 50,
color: AppColor.textWhite,
),
),
// Decorative floating dots
...List.generate(6, (index) {
final radius = 120.0;
return Positioned(
left:
100 +
radius *
0.8 *
(index.isEven ? 1 : -1) *
(index / 6),
top:
100 +
radius *
0.6 *
(index.isOdd ? 1 : -1) *
(index / 6),
child: Container(
width: 8 + (index % 3) * 4,
height: 8 + (index % 3) * 4,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: [
AppColor.primary,
AppColor.error,
AppColor.warning,
][index % 3].withOpacity(0.6),
),
),
);
}),
],
),
);
},
),
const SizedBox(height: 40),
// Animated Title
FadeTransition(
opacity: _fadeAnimation,
child: Text(
widget.title ?? 'Ups! Ada Yang Salah',
style: AppStyle.h2.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary, // warna solid
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 16),
// Animated Message
SlideTransition(
position: _slideAnimation,
child: FadeTransition(
opacity: _fadeAnimation,
child: Container(
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.08),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
border: Border.all(
color: AppColor.border.withOpacity(0.5),
),
),
child: Column(
children: [
Text(
widget.message ??
'Sepertinya ada masalah teknis yang tidak terduga. Jangan khawatir, tim kami sedang bekerja keras untuk memperbaikinya!',
style: AppStyle.lg.copyWith(
color: AppColor.textSecondary,
height: 1.6,
),
textAlign: TextAlign.center,
),
if (widget.errorCode != null) ...[
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColor.error.withOpacity(0.1),
AppColor.warning.withOpacity(0.1),
],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppColor.error.withOpacity(0.3),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.code,
size: 16,
color: AppColor.error,
),
const SizedBox(width: 8),
Text(
'Kode Error: ${widget.errorCode}',
style: AppStyle.sm.copyWith(
color: AppColor.error,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
],
),
),
),
),
const SizedBox(height: 50),
// Animated Buttons
SlideTransition(
position: _slideAnimation,
child: FadeTransition(
opacity: _fadeAnimation,
child: Column(
children: [
// Retry Button with gradient
if (widget.onRetry != null)
Container(
width: double.infinity,
height: 60,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.4),
blurRadius: 15,
offset: const Offset(0, 8),
),
],
),
child: ElevatedButton.icon(
onPressed: widget.onRetry,
icon: const Icon(
Icons.refresh_rounded,
color: AppColor.textWhite,
size: 24,
),
label: Text(
'Coba Lagi',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
),
const SizedBox(height: 16),
// Back Button with modern design
if (widget.onBack != null)
Container(
width: double.infinity,
height: 60,
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(16),
border: Border.all(
width: 2,
color: AppColor.primary.withOpacity(0.3),
),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: OutlinedButton.icon(
onPressed: widget.onBack,
icon: Icon(
Icons.arrow_back_ios_rounded,
color: AppColor.primary,
size: 20,
),
label: Text(
'Kembali',
style: AppStyle.xl.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.bold,
),
),
style: OutlinedButton.styleFrom(
backgroundColor: Colors.transparent,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
),
],
),
),
),
const SizedBox(height: 40),
// Help text with icon
FadeTransition(
opacity: _fadeAnimation,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.info.withOpacity(0.05),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.info.withOpacity(0.1)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.help_outline_rounded,
size: 18,
color: AppColor.info,
),
const SizedBox(width: 8),
Flexible(
child: Text(
'Butuh bantuan? Hubungi tim support kami',
style: AppStyle.sm.copyWith(
color: AppColor.info,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
),
],
),
),
),
],
),
),
),
),
);
}
}
// Usage Example dengan berbagai variasi
class ErrorPageExamples extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
// Network Error
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ErrorPage(
title: 'Koneksi Terputus',
message:
'Sepertinya koneksi internet Anda bermasalah. Periksa jaringan dan coba lagi.',
errorCode: 'NET_404',
errorIcon: Icons.wifi_off_rounded,
onRetry: () => Navigator.pop(context),
onBack: () => Navigator.pop(context),
),
),
),
child: Text('Network Error'),
),
// Server Error
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ErrorPage(
title: 'Server Sibuk',
message:
'Server sedang mengalami gangguan. Tim kami sedang memperbaikinya.',
errorCode: 'SRV_500',
errorIcon: Icons.dns_rounded,
onRetry: () => Navigator.pop(context),
onBack: () => Navigator.pop(context),
),
),
),
child: Text('Server Error'),
),
],
);
}
}

View File

@ -1,43 +1,20 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import '../../../application/analytic/category_analytic_loader/category_analytic_loader_bloc.dart';
import '../../../application/analytic/profit_loss_loader/profit_loss_loader_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import 'widgets/cash_flow.dart';
import 'widgets/category.dart';
import 'widgets/product.dart';
import 'widgets/profit_loss.dart';
import 'widgets/summary_card.dart';
@RoutePage()
class FinancePage extends StatefulWidget implements AutoRouteWrapper {
class FinancePage extends StatefulWidget {
const FinancePage({super.key});
@override
State<FinancePage> createState() => _FinancePageState();
@override
Widget wrappedRoute(BuildContext context) => MultiBlocProvider(
providers: [
BlocProvider(
create: (_) =>
getIt<ProfitLossLoaderBloc>()..add(ProfitLossLoaderEvent.fetched()),
),
BlocProvider(
create: (context) =>
getIt<CategoryAnalyticLoaderBloc>()
..add(CategoryAnalyticLoaderEvent.fetched()),
),
],
child: this,
);
}
class _FinancePageState extends State<FinancePage>
@ -113,83 +90,69 @@ class _FinancePageState extends State<FinancePage>
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: BlocBuilder<ProfitLossLoaderBloc, ProfitLossLoaderState>(
builder: (context, state) {
return CustomScrollView(
slivers: [
// SliverAppBar with animated background
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
elevation: 0,
flexibleSpace: CustomAppBar(title: 'Keuangan'),
),
body: CustomScrollView(
slivers: [
// SliverAppBar with animated background
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
elevation: 0,
flexibleSpace: CustomAppBar(title: 'Keuangan'),
),
// Header dengan filter periode
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: _buildPeriodSelector(),
),
),
// Header dengan filter periode
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: _buildPeriodSelector(),
),
),
// Summary Cards
SliverToBoxAdapter(
child: SlideTransition(
position: _slideAnimation,
child: _buildSummaryCards(state.profitLoss.summary),
),
),
// Summary Cards
SliverToBoxAdapter(
child: SlideTransition(
position: _slideAnimation,
child: _buildSummaryCards(),
),
),
// Cash Flow Analysis
SliverToBoxAdapter(
child: ScaleTransition(
scale: _scaleAnimation,
child: FinanceCashFlow(dailyData: state.profitLoss.data),
),
),
// Cash Flow Analysis
SliverToBoxAdapter(
child: ScaleTransition(
scale: _scaleAnimation,
child: FinanceCashFlow(),
),
),
// Profit Loss Detail
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: FinanceProfitLoss(data: state.profitLoss.summary),
),
),
// Profit Loss Detail
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: FinanceProfitLoss(),
),
),
BlocBuilder<
CategoryAnalyticLoaderBloc,
CategoryAnalyticLoaderState
>(
builder: (context, stateCategory) {
return SliverToBoxAdapter(
child: SlideTransition(
position: _slideAnimation,
child: FinanceCategory(
categories: stateCategory.categoryAnalytic.data,
),
),
);
},
),
// Transaction Categories
SliverToBoxAdapter(
child: SlideTransition(
position: _slideAnimation,
child: FinanceCategory(),
),
),
// Product Analysis Section
SliverToBoxAdapter(
child: SlideTransition(
position: _slideAnimation,
child: _buildProductAnalysis(state.profitLoss.productData),
),
),
// Monthly Comparison
SliverToBoxAdapter(
child: ScaleTransition(
scale: _scaleAnimation,
child: _buildMonthlyComparison(),
),
),
// Transaction Categories
// Bottom spacing
const SliverToBoxAdapter(child: SizedBox(height: 100)),
],
);
},
// Bottom spacing
const SliverToBoxAdapter(child: SizedBox(height: 100)),
],
),
);
}
@ -247,7 +210,7 @@ class _FinancePageState extends State<FinancePage>
);
}
Widget _buildSummaryCards(ProfitLossSummary summary) {
Widget _buildSummaryCards() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
@ -257,9 +220,10 @@ class _FinancePageState extends State<FinancePage>
Expanded(
child: FinanceSummaryCard(
title: 'Total Pendapatan',
amount: summary.totalRevenue.currencyFormatRp,
amount: 'Rp 25.840.000',
icon: LineIcons.arrowUp,
color: AppColor.success,
change: '+12.5%',
isPositive: true,
),
),
@ -267,9 +231,10 @@ class _FinancePageState extends State<FinancePage>
Expanded(
child: FinanceSummaryCard(
title: 'Total Pengeluaran',
amount: summary.totalCost.currencyFormatRp,
amount: 'Rp 18.320.000',
icon: LineIcons.arrowDown,
color: AppColor.error,
change: '+8.2%',
isPositive: false,
),
),
@ -281,9 +246,10 @@ class _FinancePageState extends State<FinancePage>
Expanded(
child: FinanceSummaryCard(
title: 'Keuntungan Bersih',
amount: summary.netProfit.currencyFormatRp,
amount: 'Rp 7.520.000',
icon: LineIcons.lineChart,
color: AppColor.info,
change: '+15.3%',
isPositive: true,
),
),
@ -291,9 +257,10 @@ class _FinancePageState extends State<FinancePage>
Expanded(
child: FinanceSummaryCard(
title: 'Margin Profit',
amount: '${summary.profitabilityRatio.round()}%',
amount: '29.1%',
icon: LineIcons.percent,
color: AppColor.warning,
change: '+2.1%',
isPositive: true,
),
),
@ -304,7 +271,7 @@ class _FinancePageState extends State<FinancePage>
);
}
Widget _buildProductAnalysis(List<ProfitLossProductData> products) {
Widget _buildMonthlyComparison() {
return Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(20),
@ -328,41 +295,138 @@ class _FinancePageState extends State<FinancePage>
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.info.withOpacity(0.1),
color: AppColor.warning.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
LineIcons.shoppingBag,
color: AppColor.info,
LineIcons.calendarCheck,
color: AppColor.warning,
size: 20,
),
),
const SizedBox(width: 12),
Text(
'Analisis Produk',
'Perbandingan Bulanan',
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
),
const Spacer(),
TextButton(
onPressed: () {},
child: Text(
'Lihat Semua',
style: AppStyle.sm.copyWith(color: AppColor.primary),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: _buildComparisonCard(
'Bulan Ini',
'Rp 7.52M',
'+15.3%',
true,
AppColor.primary,
),
),
const SizedBox(width: 12),
Expanded(
child: _buildComparisonCard(
'Bulan Lalu',
'Rp 6.53M',
'-2.1%',
false,
AppColor.textSecondary,
),
),
],
),
// Product list
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.only(top: 12),
itemCount: products.length,
separatorBuilder: (context, index) => const SizedBox(height: 12),
itemBuilder: (context, index) {
final product = products[index];
return ProfitLossProduct(product: product);
},
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.success.withOpacity(0.05),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.success.withOpacity(0.2)),
),
child: Row(
children: [
const Icon(
LineIcons.thumbsUp,
color: AppColor.success,
size: 20,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Performa Bagus!',
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.success,
),
),
Text(
'Keuntungan meningkat 15.3% dari bulan lalu',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
],
),
),
],
),
),
],
),
);
}
Widget _buildComparisonCard(
String period,
String amount,
String change,
bool isPositive,
Color color,
) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: color.withOpacity(0.05),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: color.withOpacity(0.2)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
period,
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
),
const SizedBox(height: 8),
Text(
amount,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: color,
),
),
const SizedBox(height: 4),
Row(
children: [
Icon(
isPositive ? LineIcons.arrowUp : LineIcons.arrowDown,
size: 14,
color: isPositive ? AppColor.success : AppColor.error,
),
const SizedBox(width: 4),
Text(
change,
style: AppStyle.xs.copyWith(
color: isPositive ? AppColor.success : AppColor.error,
fontWeight: FontWeight.w600,
),
),
],
),
],
),

View File

@ -1,23 +1,14 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import 'package:intl/intl.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
class FinanceCashFlow extends StatelessWidget {
final List<ProfitLossDailyData> dailyData;
const FinanceCashFlow({super.key, required this.dailyData});
const FinanceCashFlow({super.key});
@override
Widget build(BuildContext context) {
// Calculate totals from daily data
final totalCashIn = _calculateTotalCashIn();
final totalCashOut = _calculateTotalCashOut();
final netFlow = totalCashIn - totalCashOut;
return Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(20),
@ -79,7 +70,7 @@ class FinanceCashFlow extends StatelessWidget {
Expanded(
child: _buildCashFlowIndicator(
'Cash In',
_formatCurrency(totalCashIn),
'Rp 28.5M',
LineIcons.arrowUp,
AppColor.success,
),
@ -88,7 +79,7 @@ class FinanceCashFlow extends StatelessWidget {
Expanded(
child: _buildCashFlowIndicator(
'Cash Out',
_formatCurrency(totalCashOut),
'Rp 21.2M',
LineIcons.arrowDown,
AppColor.error,
),
@ -97,7 +88,7 @@ class FinanceCashFlow extends StatelessWidget {
Expanded(
child: _buildCashFlowIndicator(
'Net Flow',
_formatCurrency(netFlow),
'Rp 7.3M',
LineIcons.equals,
AppColor.info,
),
@ -119,7 +110,7 @@ class FinanceCashFlow extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Grafik Cash Flow ${dailyData.length} Hari Terakhir',
'Grafik Cash Flow 7 Hari Terakhir',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w600,
@ -127,9 +118,207 @@ class FinanceCashFlow extends StatelessWidget {
),
const SizedBox(height: 16),
Expanded(
child: dailyData.isEmpty
? _buildEmptyChart()
: LineChart(_buildLineChartData()),
child: LineChart(
LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: false,
horizontalInterval: 5000000, // 5M interval
getDrawingHorizontalLine: (value) {
return FlLine(
color: AppColor.borderLight,
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
show: true,
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
interval: 1,
getTitlesWidget: (double value, TitleMeta meta) {
const style = TextStyle(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 10,
);
Widget text;
switch (value.toInt()) {
case 0:
text = const Text('Sen', style: style);
break;
case 1:
text = const Text('Sel', style: style);
break;
case 2:
text = const Text('Rab', style: style);
break;
case 3:
text = const Text('Kam', style: style);
break;
case 4:
text = const Text('Jum', style: style);
break;
case 5:
text = const Text('Sab', style: style);
break;
case 6:
text = const Text('Min', style: style);
break;
default:
text = const Text('', style: style);
break;
}
return SideTitleWidget(meta: meta, child: text);
},
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
interval: 10000000, // 10M interval
reservedSize: 42,
getTitlesWidget: (double value, TitleMeta meta) {
return Text(
'${(value / 1000000).toInt()}M',
style: const TextStyle(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 10,
),
textAlign: TextAlign.left,
);
},
),
),
),
borderData: FlBorderData(
show: true,
border: Border.all(color: AppColor.borderLight),
),
minX: 0,
maxX: 6,
minY: -5000000,
maxY: 30000000,
lineBarsData: [
// Cash In Line
LineChartBarData(
spots: const [
FlSpot(0, 25000000), // Monday
FlSpot(1, 22000000), // Tuesday
FlSpot(2, 28000000), // Wednesday
FlSpot(3, 24000000), // Thursday
FlSpot(4, 30000000), // Friday
FlSpot(5, 18000000), // Saturday
FlSpot(6, 26000000), // Sunday
],
isCurved: true,
gradient: LinearGradient(
colors: [
AppColor.success.withOpacity(0.8),
AppColor.success,
],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: AppColor.success,
strokeWidth: 2,
strokeColor: AppColor.white,
);
},
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
AppColor.success.withOpacity(0.1),
AppColor.success.withOpacity(0.0),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
// Cash Out Line
LineChartBarData(
spots: const [
FlSpot(0, 20000000), // Monday
FlSpot(1, 18000000), // Tuesday
FlSpot(2, 23000000), // Wednesday
FlSpot(3, 19000000), // Thursday
FlSpot(4, 25000000), // Friday
FlSpot(5, 15000000), // Saturday
FlSpot(6, 21000000), // Sunday
],
isCurved: true,
gradient: LinearGradient(
colors: [
AppColor.error.withOpacity(0.8),
AppColor.error,
],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: AppColor.error,
strokeWidth: 2,
strokeColor: AppColor.white,
);
},
),
),
// Net Flow Line
LineChartBarData(
spots: const [
FlSpot(0, 5000000), // Monday
FlSpot(1, 4000000), // Tuesday
FlSpot(2, 5000000), // Wednesday
FlSpot(3, 5000000), // Thursday
FlSpot(4, 5000000), // Friday
FlSpot(5, 3000000), // Saturday
FlSpot(6, 5000000), // Sunday
],
isCurved: true,
gradient: LinearGradient(
colors: [
AppColor.info.withOpacity(0.8),
AppColor.info,
],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: AppColor.info,
strokeWidth: 2,
strokeColor: AppColor.white,
);
},
),
),
],
),
),
),
const SizedBox(height: 12),
// Legend
@ -151,273 +340,6 @@ class FinanceCashFlow extends StatelessWidget {
);
}
LineChartData _buildLineChartData() {
final maxValue = _getMaxChartValue();
final minValue = _getMinChartValue();
return LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: false,
horizontalInterval: (maxValue / 5).roundToDouble(),
getDrawingHorizontalLine: (value) {
return FlLine(color: AppColor.borderLight, strokeWidth: 1);
},
),
titlesData: FlTitlesData(
show: true,
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
interval: 1,
getTitlesWidget: (double value, TitleMeta meta) {
final index = value.toInt();
if (index >= 0 && index < dailyData.length) {
final date = DateTime.parse(dailyData[index].date);
final dayName = _getDayName(date.weekday);
return SideTitleWidget(
meta: meta,
child: Text(
dayName,
style: const TextStyle(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 10,
),
),
);
}
return SideTitleWidget(meta: meta, child: Text(''));
},
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
interval: (maxValue / 3).roundToDouble(),
reservedSize: 42,
getTitlesWidget: (double value, TitleMeta meta) {
return Text(
_formatChartValue(value),
style: const TextStyle(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 10,
),
textAlign: TextAlign.left,
);
},
),
),
),
borderData: FlBorderData(
show: true,
border: Border.all(color: AppColor.borderLight),
),
minX: 0,
maxX: (dailyData.length - 1).toDouble(),
minY: minValue,
maxY: maxValue,
lineBarsData: [
// Cash In Line (Revenue)
LineChartBarData(
spots: _buildCashInSpots(),
isCurved: true,
gradient: LinearGradient(
colors: [AppColor.success.withOpacity(0.8), AppColor.success],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: AppColor.success,
strokeWidth: 2,
strokeColor: AppColor.white,
);
},
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
AppColor.success.withOpacity(0.1),
AppColor.success.withOpacity(0.0),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
// Cash Out Line (Total Cost)
LineChartBarData(
spots: _buildCashOutSpots(),
isCurved: true,
gradient: LinearGradient(
colors: [AppColor.error.withOpacity(0.8), AppColor.error],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: AppColor.error,
strokeWidth: 2,
strokeColor: AppColor.white,
);
},
),
),
// Net Flow Line (Net Profit)
LineChartBarData(
spots: _buildNetFlowSpots(),
isCurved: true,
gradient: LinearGradient(
colors: [AppColor.info.withOpacity(0.8), AppColor.info],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 4,
color: AppColor.info,
strokeWidth: 2,
strokeColor: AppColor.white,
);
},
),
),
],
);
}
Widget _buildEmptyChart() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
LineIcons.lineChart,
size: 48,
color: AppColor.textSecondary.withOpacity(0.3),
),
const SizedBox(height: 12),
Text(
'Tidak ada data untuk ditampilkan',
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
),
],
),
);
}
// Helper methods for calculating data
int _calculateTotalCashIn() {
return dailyData.fold(0, (sum, data) => sum + data.revenue);
}
int _calculateTotalCashOut() {
return dailyData.fold(
0,
(sum, data) => sum + data.cost + data.tax + data.discount,
);
}
double _getMaxChartValue() {
if (dailyData.isEmpty) return 30000000;
final maxRevenue = dailyData
.map((e) => e.revenue)
.reduce((a, b) => a > b ? a : b);
final maxCost = dailyData
.map((e) => e.cost + e.tax + e.discount)
.reduce((a, b) => a > b ? a : b);
final maxValue = maxRevenue > maxCost ? maxRevenue : maxCost;
return (maxValue * 1.2).toDouble(); // Add 20% padding
}
double _getMinChartValue() {
if (dailyData.isEmpty) return -5000000;
final minNetProfit = dailyData
.map((e) => e.netProfit)
.reduce((a, b) => a < b ? a : b);
return minNetProfit < 0 ? (minNetProfit * 1.2).toDouble() : 0;
}
List<FlSpot> _buildCashInSpots() {
return dailyData.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.revenue.toDouble());
}).toList();
}
List<FlSpot> _buildCashOutSpots() {
return dailyData.asMap().entries.map((entry) {
final totalCost =
entry.value.cost + entry.value.tax + entry.value.discount;
return FlSpot(entry.key.toDouble(), totalCost.toDouble());
}).toList();
}
List<FlSpot> _buildNetFlowSpots() {
return dailyData.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.netProfit.toDouble());
}).toList();
}
String _getDayName(int weekday) {
switch (weekday) {
case 1:
return 'Sen';
case 2:
return 'Sel';
case 3:
return 'Rab';
case 4:
return 'Kam';
case 5:
return 'Jum';
case 6:
return 'Sab';
case 7:
return 'Min';
default:
return '';
}
}
String _formatChartValue(double value) {
if (value.abs() >= 1000000) {
return '${(value / 1000000).toStringAsFixed(0)}M';
} else if (value.abs() >= 1000) {
return '${(value / 1000).toStringAsFixed(0)}K';
} else {
return value.toStringAsFixed(0);
}
}
String _formatCurrency(int amount) {
if (amount.abs() >= 1000000000) {
return 'Rp ${(amount / 1000000000).toStringAsFixed(1)}B';
} else if (amount.abs() >= 1000000) {
return 'Rp ${(amount / 1000000).toStringAsFixed(1)}M';
} else if (amount.abs() >= 1000) {
return 'Rp ${(amount / 1000).toStringAsFixed(1)}K';
} else {
return 'Rp ${NumberFormat('#,###', 'id_ID').format(amount)}';
}
}
Widget _buildChartLegend(String label, Color color) {
return Row(
mainAxisSize: MainAxisSize.min,

View File

@ -1,21 +1,33 @@
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import 'package:intl/intl.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../components/widgets/empty_widget.dart';
class FinanceCategory extends StatelessWidget {
final List<CategoryAnalyticItem> categories;
const FinanceCategory({super.key, required this.categories});
const FinanceCategory({super.key});
@override
Widget build(BuildContext context) {
final totalRevenue = _calculateTotalRevenue();
final sortedCategories = _sortCategoriesByRevenue();
final categories = [
{
'name': 'Makanan & Minuman',
'amount': 'Rp 18.5M',
'percentage': 72,
'color': AppColor.primary,
},
{
'name': 'Produk Retail',
'amount': 'Rp 4.2M',
'percentage': 16,
'color': AppColor.secondary,
},
{
'name': 'Jasa & Lainnya',
'amount': 'Rp 3.1M',
'percentage': 12,
'color': AppColor.info,
},
];
return Container(
margin: const EdgeInsets.all(16),
@ -58,25 +70,25 @@ class FinanceCategory extends StatelessWidget {
),
const SizedBox(height: 20),
// Show empty state if no categories
if (categories.isEmpty)
_buildEmptyState()
else
...sortedCategories.asMap().entries.map(
(entry) => _buildCategoryItem(
entry.value,
_calculatePercentage(entry.value.totalRevenue, totalRevenue),
_getCategoryColor(entry.key),
),
),
...categories
.map(
(category) => _buildCategoryItem(
category['name'] as String,
category['amount'] as String,
category['percentage'] as int,
category['color'] as Color,
),
)
.toList(),
],
),
);
}
Widget _buildCategoryItem(
CategoryAnalyticItem category,
double percentage,
String name,
String amount,
int percentage,
Color color,
) {
return Container(
@ -86,59 +98,30 @@ class FinanceCategory extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Container(
width: 12,
height: 12,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
category.categoryName,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 2),
Text(
'${category.productCount} produk • ${category.orderCount} pesanan',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
),
),
],
),
),
],
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
Row(
children: [
Text(
category.totalRevenue.currencyFormatRp,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
Container(
width: 12,
height: 12,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(width: 12),
Text(
'${NumberFormat('#,###', 'id_ID').format(category.totalQuantity)} unit',
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
name,
style: AppStyle.md.copyWith(fontWeight: FontWeight.w600),
),
],
),
Text(
amount,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: color,
),
),
],
),
const SizedBox(height: 8),
@ -152,7 +135,7 @@ class FinanceCategory extends StatelessWidget {
Align(
alignment: Alignment.centerRight,
child: Text(
'${percentage.toStringAsFixed(1)}%',
'$percentage%',
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
),
),
@ -160,48 +143,4 @@ class FinanceCategory extends StatelessWidget {
),
);
}
Widget _buildEmptyState() {
return EmptyWidget(
title: 'Belum ada data kategori',
message: 'Data kategori penjualan akan muncul di sini',
);
}
// Helper methods
int _calculateTotalRevenue() {
return categories.fold(0, (sum, category) => sum + category.totalRevenue);
}
List<CategoryAnalyticItem> _sortCategoriesByRevenue() {
final sorted = List<CategoryAnalyticItem>.from(categories);
sorted.sort((a, b) => b.totalRevenue.compareTo(a.totalRevenue));
return sorted;
}
double _calculatePercentage(int categoryRevenue, int totalRevenue) {
if (totalRevenue == 0) return 0;
return (categoryRevenue / totalRevenue) * 100;
}
Color _getCategoryColor(int index) {
// Predefined color palette for categories
const colors = [
AppColor.primary,
AppColor.secondary,
AppColor.success,
AppColor.warning,
AppColor.error,
AppColor.info,
];
// Generate additional colors if needed
if (index < colors.length) {
return colors[index];
} else {
// Generate colors based on index for unlimited categories
final hue = (index * 137.5) % 360; // Golden angle approximation
return HSLColor.fromAHSL(1.0, hue, 0.7, 0.5).toColor();
}
}
}

View File

@ -1,148 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
class ProfitLossProduct extends StatelessWidget {
final ProfitLossProductData product;
const ProfitLossProduct({super.key, required this.product});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.background,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.border.withOpacity(0.5)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Product header
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.productName,
style: AppStyle.md.copyWith(fontWeight: FontWeight.bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 2),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Text(
product.categoryName,
style: AppStyle.xs.copyWith(color: AppColor.primary),
),
),
],
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${product.quantitySold} terjual',
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
),
Text(
'${product.grossProfitMargin.toStringAsFixed(1)}%',
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: product.grossProfitMargin > 25
? AppColor.success
: product.grossProfitMargin > 15
? AppColor.warning
: AppColor.error,
),
),
],
),
],
),
const SizedBox(height: 16),
// Financial metrics
Row(
children: [
Expanded(
child: _buildMetricColumn(
'Pendapatan',
product.revenue.currencyFormatRp,
AppColor.success,
),
),
Expanded(
child: _buildMetricColumn(
'Biaya',
product.cost.currencyFormatRp,
AppColor.error,
),
),
Expanded(
child: _buildMetricColumn(
'Laba Kotor',
product.grossProfit.currencyFormatRp,
AppColor.info,
),
),
],
),
const SizedBox(height: 12),
// Average metrics
Row(
children: [
Expanded(
child: _buildMetricColumn(
'Harga Rata-rata',
product.averagePrice.currencyFormatRp,
AppColor.textSecondary,
),
),
Expanded(
child: _buildMetricColumn(
'Laba per Unit',
product.profitPerUnit.currencyFormatRp,
AppColor.primary,
),
),
const Expanded(child: SizedBox()),
],
),
],
),
);
}
Widget _buildMetricColumn(String label, String value, Color color) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: AppStyle.xs.copyWith(color: AppColor.textSecondary)),
const SizedBox(height: 2),
Text(
value,
style: AppStyle.sm.copyWith(
fontWeight: FontWeight.w600,
color: color,
),
),
],
);
}
}

View File

@ -1,14 +1,10 @@
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
class FinanceProfitLoss extends StatelessWidget {
final ProfitLossSummary data;
const FinanceProfitLoss({super.key, required this.data});
const FinanceProfitLoss({super.key});
@override
Widget build(BuildContext context) {
@ -53,77 +49,52 @@ class FinanceProfitLoss extends StatelessWidget {
),
const SizedBox(height: 20),
// Total Revenue (Penjualan Kotor)
_buildPLItem(
'Penjualan Kotor',
data.totalRevenue.currencyFormatRp,
'Rp 25.840.000',
AppColor.success,
true,
),
// Discount (Diskon & Retur)
_buildPLItem(
'Diskon & Retur',
'- ${data.totalDiscount.currencyFormatRp}',
AppColor.error,
false,
),
_buildPLItem('Diskon & Retur', '- Rp 560.000', AppColor.error, false),
const Divider(height: 24),
// Net Sales (Penjualan Bersih = Total Revenue - Discount)
_buildPLItem(
'Penjualan Bersih',
(data.totalRevenue - data.totalDiscount).currencyFormatRp,
'Rp 25.280.000',
AppColor.textPrimary,
true,
isHeader: true,
),
const SizedBox(height: 12),
// Cost of Goods Sold (HPP)
_buildPLItem(
'HPP (Harga Pokok Penjualan)',
'- ${data.totalCost.currencyFormatRp}',
'- Rp 15.120.000',
AppColor.error,
false,
),
const Divider(height: 24),
// Gross Profit (Laba Kotor)
_buildPLItem(
'Laba Kotor',
data.grossProfit.currencyFormatRp,
'Rp 10.160.000',
AppColor.success,
true,
isHeader: true,
showPercentage: true,
percentage: '${data.grossProfitMargin.toStringAsFixed(1)}%',
),
const SizedBox(height: 12),
// Operational Cost (Biaya Operasional) - calculated as difference
_buildPLItem(
'Biaya Operasional',
'- ${_calculateOperationalCost().currencyFormatRp}',
'- Rp 2.640.000',
AppColor.error,
false,
),
const Divider(height: 24),
// Net Profit (Laba Bersih)
_buildPLItem(
'Laba Bersih',
data.netProfit.currencyFormatRp,
'Rp 7.520.000',
AppColor.primary,
true,
isHeader: true,
showPercentage: true,
percentage: '${data.netProfitMargin.round()}%',
percentage: '29.8%',
),
],
),
@ -184,9 +155,4 @@ class FinanceProfitLoss extends StatelessWidget {
),
);
}
// Calculate operational cost as the difference between gross profit and net profit
int _calculateOperationalCost() {
return data.grossProfit - data.netProfit - data.totalTax;
}
}

View File

@ -9,6 +9,7 @@ class FinanceSummaryCard extends StatelessWidget {
required this.amount,
required this.icon,
required this.color,
required this.change,
required this.isPositive,
});
@ -16,6 +17,7 @@ class FinanceSummaryCard extends StatelessWidget {
final String amount;
final IconData icon;
final Color color;
final String change;
final bool isPositive;
@override
@ -48,6 +50,22 @@ class FinanceSummaryCard extends StatelessWidget {
),
child: Icon(icon, color: color, size: 20),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: isPositive
? AppColor.success.withOpacity(0.1)
: AppColor.error.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Text(
change,
style: AppStyle.xs.copyWith(
color: isPositive ? AppColor.success : AppColor.error,
fontWeight: FontWeight.w600,
),
),
),
],
),
const SizedBox(height: 12),

View File

@ -1,13 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:math' as math;
import '../../../../application/auth/auth_bloc.dart';
import '../../../../common/constant/app_constant.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/painter/wave_painter.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/auth/auth.dart';
import '../../../components/spacer/spacer.dart';
class HomeHeader extends StatefulWidget {
@ -106,47 +102,43 @@ class _HomeHeaderState extends State<HomeHeader> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
return AnimatedBuilder(
animation: Listenable.merge([
_particleController,
_waveController,
_breathController,
]),
builder: (context, child) {
return Container(
height: 280,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColor.primary,
AppColor.primaryLight,
AppColor.primaryLight.withOpacity(0.8),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: const [0.0, 0.7, 1.0],
),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
return AnimatedBuilder(
animation: Listenable.merge([
_particleController,
_waveController,
_breathController,
]),
builder: (context, child) {
return Container(
height: 280,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColor.primary,
AppColor.primaryLight,
AppColor.primaryLight.withOpacity(0.8),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: const [0.0, 0.7, 1.0],
),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
child: Stack(
children: [
// Enhanced animated background
_buildAnimatedBackground(),
],
),
child: Stack(
children: [
// Enhanced animated background
_buildAnimatedBackground(),
// Main content
SafeArea(child: _buildContent(context, state.user)),
],
),
);
},
// Main content
SafeArea(child: _buildContent(context)),
],
),
);
},
);
@ -263,7 +255,7 @@ class _HomeHeaderState extends State<HomeHeader> with TickerProviderStateMixin {
);
}
Widget _buildContent(BuildContext context, User user) {
Widget _buildContent(BuildContext context) {
String greeting(BuildContext context) {
final hour = DateTime.now().hour;
@ -299,7 +291,7 @@ class _HomeHeaderState extends State<HomeHeader> with TickerProviderStateMixin {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppConstant.appName,
'AppSkel POS Owner',
style: AppStyle.lg.copyWith(
color: AppColor.white.withOpacity(0.9),
fontWeight: FontWeight.w600,
@ -315,7 +307,7 @@ class _HomeHeaderState extends State<HomeHeader> with TickerProviderStateMixin {
),
const SpaceHeight(2),
Text(
user.role.toTitleCase,
'Manager',
style: AppStyle.sm.copyWith(
color: AppColor.white.withOpacity(0.7),
fontSize: 11,
@ -391,7 +383,7 @@ class _HomeHeaderState extends State<HomeHeader> with TickerProviderStateMixin {
),
const SpaceHeight(2),
Text(
'${user.name}! đź‘‹',
'Vira Vania! đź‘‹',
style: AppStyle.h4.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w800,

View File

@ -1,53 +1,130 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import 'package:shimmer/shimmer.dart';
import '../../../application/category/category_loader/category_loader_bloc.dart';
import '../../../application/product/product_loader/product_loader_bloc.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/category/category.dart';
import '../../../domain/product/product.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import '../../components/widgets/empty_widget.dart';
import 'widgets/category_delegate.dart';
import 'widgets/product_card.dart';
import 'widgets/product_tile.dart';
@RoutePage()
class ProductPage extends StatefulWidget implements AutoRouteWrapper {
class ProductPage extends StatefulWidget {
const ProductPage({super.key});
@override
State<ProductPage> createState() => _ProductPageState();
@override
Widget wrappedRoute(BuildContext context) => MultiBlocProvider(
providers: [
BlocProvider(
create: (context) =>
getIt<CategoryLoaderBloc>()..add(CategoryLoaderEvent.fetched()),
),
BlocProvider(
create: (context) =>
getIt<ProductLoaderBloc>()
..add(ProductLoaderEvent.fetched(isRefresh: true)),
),
],
child: this,
);
}
enum ViewType { grid, list }
class _ProductPageState extends State<ProductPage>
with TickerProviderStateMixin {
Category selectedCategory = Category.addAllData();
String selectedCategory = 'Semua';
List<String> categories = ['Semua', 'Makanan', 'Minuman', 'Snack', 'Dessert'];
ViewType currentViewType = ViewType.grid;
ScrollController scrollController = ScrollController();
// Sample product data
List<Product> products = [
Product(
id: '1',
name: 'Nasi Goreng Special',
price: 25000,
category: 'Makanan',
stock: 50,
imageUrl: 'assets/images/nasi_goreng.jpg',
isActive: true,
),
Product(
id: '8',
name: 'Nasi Goreng',
price: 15000,
category: 'Makanan',
stock: 50,
imageUrl: 'assets/images/nasi_goreng.jpg',
isActive: true,
),
Product(
id: '9',
name: 'Nasi Goreng Telor',
price: 18000,
category: 'Makanan',
stock: 50,
imageUrl: 'assets/images/nasi_goreng.jpg',
isActive: true,
),
Product(
id: '10',
name: 'Mie Goreng ',
price: 18000,
category: 'Makanan',
stock: 50,
imageUrl: 'assets/images/nasi_goreng.jpg',
isActive: true,
),
Product(
id: '2',
name: 'Es Teh Manis',
price: 8000,
category: 'Minuman',
stock: 100,
imageUrl: 'assets/images/es_teh.jpg',
isActive: true,
),
Product(
id: '6',
name: 'Es Jeruk',
price: 10000,
category: 'Minuman',
stock: 100,
imageUrl: 'assets/images/es_teh.jpg',
isActive: true,
),
Product(
id: '7',
name: 'Es Kelapa',
price: 12000,
category: 'Minuman',
stock: 100,
imageUrl: 'assets/images/es_teh.jpg',
isActive: true,
),
Product(
id: '3',
name: 'Keripik Singkong',
price: 15000,
category: 'Snack',
stock: 25,
imageUrl: 'assets/images/keripik.jpg',
isActive: true,
),
Product(
id: '4',
name: 'Es Krim Vanilla',
price: 12000,
category: 'Dessert',
stock: 30,
imageUrl: 'assets/images/ice_cream.jpg',
isActive: false,
),
Product(
id: '5',
name: 'Ayam Bakar',
price: 35000,
category: 'Makanan',
stock: 20,
imageUrl: 'assets/images/ayam_bakar.jpg',
isActive: true,
),
];
List<Product> get filteredProducts {
return products.where((product) {
bool matchesCategory =
selectedCategory == 'Semua' || product.category == selectedCategory;
return matchesCategory;
}).toList();
}
@override
initState() {
@ -55,42 +132,21 @@ class _ProductPageState extends State<ProductPage>
}
@override
Widget build(BuildContext context) {
return BlocListener<ProductLoaderBloc, ProductLoaderState>(
listenWhen: (previous, current) =>
previous.categoryId != current.categoryId,
listener: (context, state) {
context.read<ProductLoaderBloc>().add(
ProductLoaderEvent.fetched(isRefresh: true),
);
},
child: BlocBuilder<ProductLoaderBloc, ProductLoaderState>(
builder: (context, state) {
return Scaffold(
backgroundColor: AppColor.background,
body: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollEndNotification &&
scrollController.position.extentAfter == 0) {
context.read<ProductLoaderBloc>().add(
ProductLoaderEvent.fetched(),
);
return true;
}
void dispose() {
super.dispose();
}
return true;
},
child: CustomScrollView(
controller: scrollController,
slivers: [
_buildSliverAppBar(),
_buildCategoryFilter(),
_buildProductContent(state),
],
),
),
);
},
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(
slivers: [
_buildSliverAppBar(),
_buildCategoryFilter(),
_buildProductContent(),
_buildEmptyState(),
],
),
);
}
@ -104,97 +160,44 @@ class _ProductPageState extends State<ProductPage>
flexibleSpace: CustomAppBar(title: 'Produk'),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.search),
ActionIconButton(onTap: _showAddProductDialog, icon: LineIcons.plus),
ActionIconButton(
onTap: _toggleViewType,
icon: currentViewType == ViewType.grid
? LineIcons.list
: LineIcons.thLarge,
),
ActionIconButton(onTap: _showOptionsMenu, icon: LineIcons.filter),
],
);
}
Widget _buildCategoryFilter() {
return BlocBuilder<CategoryLoaderBloc, CategoryLoaderState>(
builder: (context, state) {
if (state.isFetching && state.categories.isEmpty) {
return _buildCategoryShimmer();
}
return SliverPersistentHeader(
pinned: true,
delegate: ProductCategoryHeaderDelegate(
categories: state.categories,
selectedCategory: selectedCategory,
onCategoryChanged: (category) {
setState(() {
selectedCategory = category;
});
if (category.id == Category.addAllData().id) {
context.read<ProductLoaderBloc>().add(
ProductLoaderEvent.categoryIdChanged(''),
);
} else {
context.read<ProductLoaderBloc>().add(
ProductLoaderEvent.categoryIdChanged(category.id),
);
}
},
),
);
},
);
}
Widget _buildCategoryShimmer() {
return SliverToBoxAdapter(
child: Container(
height: 60,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Row(
children: List.generate(
4,
(index) => Container(
margin: EdgeInsets.only(right: index < 3 ? 12 : 0),
width: 80,
height: 35,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
),
),
),
),
return SliverPersistentHeader(
pinned: true,
delegate: ProductCategoryHeaderDelegate(
categories: categories,
selectedCategory: selectedCategory,
onCategoryChanged: (category) {
setState(() {
selectedCategory = category;
});
},
),
);
}
Widget _buildProductContent(ProductLoaderState state) {
if (state.isFetching && state.products.isEmpty) {
return currentViewType == ViewType.grid
? _buildProductGridShimmer()
: _buildProductListShimmer();
}
if (state.products.isEmpty && !state.isFetching) {
return SliverToBoxAdapter(
child: EmptyWidget(
title: 'Tidak ada produk ditemukan',
message: 'Coba ubah filter atau tambah produk baru',
),
);
Widget _buildProductContent() {
if (filteredProducts.isEmpty) {
return const SliverToBoxAdapter(child: SizedBox.shrink());
}
return currentViewType == ViewType.grid
? _buildProductGrid(state.products)
: _buildProductList(state.products);
? _buildProductGrid()
: _buildProductList();
}
Widget _buildProductGridShimmer() {
Widget _buildProductGrid() {
return SliverPadding(
padding: const EdgeInsets.all(16.0),
sliver: SliverGrid(
@ -205,74 +208,26 @@ class _ProductPageState extends State<ProductPage>
mainAxisSpacing: 16.0,
),
delegate: SliverChildBuilderDelegate((context, index) {
return _buildProductTileShimmer();
}, childCount: 6), // Show 6 shimmer items
final product = filteredProducts[index];
return ProductTile(product: product, onTap: () {});
}, childCount: filteredProducts.length),
),
);
}
Widget _buildProductTileShimmer() {
return Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Image shimmer
Expanded(
flex: 3,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
),
),
// Content shimmer
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: 16,
color: Colors.white,
),
const SizedBox(height: 8),
Container(width: 100, height: 12, color: Colors.white),
const Spacer(),
Container(width: 80, height: 14, color: Colors.white),
],
),
),
),
],
),
),
);
}
Widget _buildProductListShimmer() {
Widget _buildProductList() {
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
sliver: SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return _buildProductListItemShimmer();
}, childCount: 8), // Show 8 shimmer items
final product = filteredProducts[index];
return _buildProductListItem(product);
}, childCount: filteredProducts.length),
),
);
}
Widget _buildProductListItemShimmer() {
Widget _buildProductListItem(Product product) {
return Container(
margin: const EdgeInsets.only(bottom: 12.0),
decoration: BoxDecoration(
@ -287,56 +242,104 @@ class _ProductPageState extends State<ProductPage>
),
],
),
child: Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
// Image shimmer
// Product Image
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
color: AppColor.background,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.asset(
product.imageUrl,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
color: AppColor.background,
child: Icon(
Icons.image_outlined,
color: AppColor.textLight,
size: 32,
),
);
},
),
),
),
const SizedBox(width: 12),
// Content shimmer
// Product Info
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: 16,
color: Colors.white,
Text(
product.name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
product.category,
style: TextStyle(fontSize: 12, color: AppColor.textLight),
),
const SizedBox(height: 8),
Container(width: 120, height: 12, color: Colors.white),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(width: 100, height: 16, color: Colors.white),
Text(
'Rp ${_formatPrice(product.price)}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
Container(
width: 60,
height: 24,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: Colors.white,
color: product.isActive
? Colors.green.withOpacity(0.1)
: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Text(
'Stock: ${product.stock}',
style: TextStyle(
fontSize: 12,
color: product.isActive
? Colors.green
: Colors.red,
fontWeight: FontWeight.w500,
),
),
),
],
),
],
),
),
const SizedBox(width: 8),
// Action button shimmer
Container(width: 24, height: 24, color: Colors.white),
// Action Button
IconButton(
onPressed: () {},
icon: const Icon(Icons.more_vert),
color: AppColor.textLight,
),
],
),
),
@ -344,33 +347,10 @@ class _ProductPageState extends State<ProductPage>
);
}
Widget _buildProductGrid(List<Product> products) {
return SliverPadding(
padding: const EdgeInsets.all(16.0),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
crossAxisSpacing: 16.0,
mainAxisSpacing: 16.0,
),
delegate: SliverChildBuilderDelegate((context, index) {
final product = products[index];
return ProductTile(product: product, onTap: () {});
}, childCount: products.length),
),
);
}
Widget _buildProductList(List<Product> products) {
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
sliver: SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
final product = products[index];
return ProductCard(product: product);
}, childCount: products.length),
),
String _formatPrice(int price) {
return price.toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
);
}
@ -381,4 +361,128 @@ class _ProductPageState extends State<ProductPage>
: ViewType.grid;
});
}
Widget _buildEmptyState() {
if (filteredProducts.isNotEmpty) {
return const SliverToBoxAdapter(child: SizedBox.shrink());
}
return SliverToBoxAdapter(
child: Container(
height: 300,
margin: const EdgeInsets.all(32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.inventory_2_outlined,
size: 64,
color: AppColor.textLight,
),
const SizedBox(height: 16),
Text(
'Tidak ada produk ditemukan',
style: TextStyle(
color: AppColor.textSecondary,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
'Coba ubah filter atau tambah produk baru',
style: TextStyle(color: AppColor.textLight, fontSize: 14),
textAlign: TextAlign.center,
),
],
),
),
);
}
void _showAddProductDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Tambah Produk'),
content: const Text(
'Dialog tambah produk akan diimplementasikan di sini',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Batal'),
),
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text('Simpan'),
),
],
),
);
}
void _showOptionsMenu() {
showModalBottomSheet(
context: context,
builder: (context) => Container(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(
currentViewType == ViewType.grid ? Icons.list : Icons.grid_view,
),
title: Text(
currentViewType == ViewType.grid
? 'Tampilan List'
: 'Tampilan Grid',
),
onTap: () {
Navigator.pop(context);
_toggleViewType();
},
),
ListTile(
leading: const Icon(Icons.sort),
title: const Text('Urutkan'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: const Icon(Icons.filter_list),
title: const Text('Filter Lanjutan'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: const Icon(Icons.download),
title: const Text('Export Data'),
onTap: () => Navigator.pop(context),
),
],
),
),
);
}
}
// Product Model
class Product {
final String id;
final String name;
final int price;
final String category;
final int stock;
final String imageUrl;
bool isActive;
Product({
required this.id,
required this.name,
required this.price,
required this.category,
required this.stock,
required this.imageUrl,
required this.isActive,
});
}

View File

@ -1,12 +1,11 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/category/category.dart';
class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
final List<Category> categories;
final Category selectedCategory;
final ValueChanged<Category> onCategoryChanged;
final List<String> categories;
final String selectedCategory;
final ValueChanged<String> onCategoryChanged;
ProductCategoryHeaderDelegate({
required this.categories,
@ -36,7 +35,7 @@ class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
return Container(
margin: const EdgeInsets.only(right: 12.0),
child: FilterChip(
label: Text(category.name),
label: Text(category),
selected: isSelected,
onSelected: (selected) => onCategoryChanged(category),
backgroundColor: AppColor.surface,
@ -65,7 +64,6 @@ class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
@override
bool shouldRebuild(ProductCategoryHeaderDelegate oldDelegate) {
return oldDelegate.categories != categories ||
oldDelegate.selectedCategory != selectedCategory;
return oldDelegate.selectedCategory != selectedCategory;
}
}

View File

@ -1,117 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/product/product.dart';
import '../../../components/image/image.dart';
class ProductCard extends StatelessWidget {
const ProductCard({super.key, required this.product, this.onTap});
final Product product;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 12.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
// Product Image
_buildProductImage(),
const SizedBox(width: 12),
// Product Info
Expanded(child: _buildProductInfo()),
],
),
),
),
);
}
Widget _buildProductImage() {
return Container(
width: 80,
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.background,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: AppNetworkImage(url: product.imageUrl, fit: BoxFit.cover),
),
);
}
Widget _buildProductInfo() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.name,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
product.description,
style: TextStyle(fontSize: 12, color: AppColor.textLight),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
product.price.currencyFormatRp,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatusColor().withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Text(
product.isActive ? 'AKTIF' : 'NONAKTIF',
style: TextStyle(
fontSize: 12,
color: _getStatusColor(),
fontWeight: FontWeight.w500,
),
),
),
],
),
],
);
}
Color _getStatusColor() {
return product.isActive ? Colors.green : Colors.red;
}
}

View File

@ -1,10 +1,8 @@
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/product/product.dart';
import '../../../components/image/image.dart';
import '../../../components/spacer/spacer.dart';
import '../product_page.dart';
class ProductTile extends StatelessWidget {
final Product product;
@ -92,7 +90,7 @@ class ProductTile extends StatelessWidget {
Widget _buildProductImage() {
return Expanded(
flex: 3,
flex: 2,
child: Container(
width: double.infinity,
decoration: const BoxDecoration(
@ -102,12 +100,12 @@ class ProductTile extends StatelessWidget {
topRight: Radius.circular(12.0),
),
),
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12.0),
topRight: Radius.circular(12.0),
),
child: AppNetworkImage(url: product.imageUrl, fit: BoxFit.cover),
child: Stack(
children: [
Center(
child: Icon(Icons.image, size: 32, color: AppColor.textLight),
),
],
),
),
);
@ -135,7 +133,7 @@ class ProductTile extends StatelessWidget {
),
const SizedBox(height: 2),
Text(
product.price.currencyFormatRp,
_formatPrice(product.price),
style: AppStyle.xs.copyWith(
color: product.isActive
? AppColor.primary
@ -153,20 +151,30 @@ class ProductTile extends StatelessWidget {
Widget _buildBottomInfo() {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: Text(
'Stok: ${product.stock}',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontSize: 9,
),
overflow: TextOverflow.ellipsis,
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
decoration: BoxDecoration(
color: _getPrinterTypeColor().withOpacity(0.1),
color: AppColor.primaryLight.withOpacity(0.1),
borderRadius: BorderRadius.circular(3.0),
),
child: Text(
product.printerType.toUpperCase(),
product.category,
style: AppStyle.xs.copyWith(
color: product.isActive
? _getPrinterTypeColor()
? AppColor.primary
: AppColor.textSecondary,
fontSize: 8,
fontWeight: FontWeight.w500,
@ -177,16 +185,7 @@ class ProductTile extends StatelessWidget {
);
}
Color _getPrinterTypeColor() {
switch (product.printerType.toLowerCase()) {
case 'kitchen':
return Colors.orange;
case 'bar':
return Colors.blue;
case 'receipt':
return AppColor.primary;
default:
return AppColor.primary;
}
String _formatPrice(int price) {
return 'Rp ${price.toString().replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]}.')}';
}
}

View File

@ -4,7 +4,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import 'package:loader_overlay/loader_overlay.dart';
import '../../../application/auth/auth_bloc.dart';
import '../../../application/auth/logout_form/logout_form_bloc.dart';
import '../../../common/theme/theme.dart';
import '../../../injection.dart';
@ -50,85 +49,78 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
},
),
],
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
return Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: AppColor.primary,
elevation: 0,
pinned: true,
expandedHeight: 264.0,
flexibleSpace: LayoutBuilder(
builder:
(BuildContext context, BoxConstraints constraints) {
// Calculate the collapse ratio
final double top = constraints.biggest.height;
final double collapsedHeight =
MediaQuery.of(context).padding.top +
kToolbarHeight;
final double expandedHeight = 264.0;
final double shrinkRatio =
((expandedHeight - top) /
(expandedHeight - collapsedHeight))
.clamp(0.0, 1.0);
child: Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: AppColor.primary,
elevation: 0,
pinned: true,
expandedHeight: 264.0,
flexibleSpace: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
// Calculate the collapse ratio
final double top = constraints.biggest.height;
final double collapsedHeight =
MediaQuery.of(context).padding.top + kToolbarHeight;
final double expandedHeight = 264.0;
final double shrinkRatio =
((expandedHeight - top) /
(expandedHeight - collapsedHeight))
.clamp(0.0, 1.0);
return FlexibleSpaceBar(
background: ProfileHeader(user: state.user),
titlePadding: const EdgeInsets.only(
left: 20,
right: 12,
bottom: 16,
return FlexibleSpaceBar(
background: ProfileHeader(),
titlePadding: const EdgeInsets.only(
left: 20,
right: 12,
bottom: 16,
),
title: Opacity(
opacity: shrinkRatio,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Profile',
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.w700,
fontSize: 18,
letterSpacing: -0.5,
color: AppColor.white,
),
title: Opacity(
opacity: shrinkRatio,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Profile',
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.w700,
fontSize: 18,
letterSpacing: -0.5,
color: AppColor.white,
),
),
ActionIconButton(
onTap: () {},
icon: LineIcons.userEdit,
),
],
),
),
);
},
),
),
SliverToBoxAdapter(
child: Column(
children: [
const SpaceHeight(20),
ProfileAccountInfo(user: state.user),
const SpaceHeight(12),
ProfileBusinessSetting(),
const SpaceHeight(12),
ProfileAppSetting(),
const SpaceHeight(12),
ProfileSupport(),
const SpaceHeight(12),
ProfileDangerZone(),
const SpaceHeight(30),
],
),
),
],
),
ActionIconButton(
onTap: () {},
icon: LineIcons.userEdit,
),
],
),
),
);
},
),
),
);
},
SliverToBoxAdapter(
child: Column(
children: [
const SpaceHeight(20),
ProfileAccountInfo(),
const SpaceHeight(12),
ProfileBusinessSetting(),
const SpaceHeight(12),
ProfileAppSetting(),
const SpaceHeight(12),
ProfileSupport(),
const SpaceHeight(12),
ProfileDangerZone(),
const SpaceHeight(30),
],
),
),
],
),
),
);
}

View File

@ -1,15 +1,11 @@
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/auth/auth.dart';
import 'divider.dart';
import 'profile_tile.dart';
class ProfileAccountInfo extends StatelessWidget {
final User user;
const ProfileAccountInfo({super.key, required this.user});
const ProfileAccountInfo({super.key});
@override
Widget build(BuildContext context) {
@ -42,9 +38,9 @@ class ProfileAccountInfo extends StatelessWidget {
),
ProfileTile(
icon: LineIcons.envelope,
icon: Icons.email_outlined,
title: 'Email',
subtitle: user.email,
subtitle: 'john.doe@business.com',
onTap: () {
// Edit email
},
@ -53,9 +49,31 @@ class ProfileAccountInfo extends StatelessWidget {
ProfileDivider(),
ProfileTile(
icon: LineIcons.calendarAlt,
icon: Icons.phone_outlined,
title: 'Phone Number',
subtitle: '+62 812 3456 7890',
onTap: () {
// Edit phone
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.location_on_outlined,
title: 'Address',
subtitle: 'Jl. Merdeka No. 123, Jakarta',
onTap: () {
// Edit address
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.calendar_today_outlined,
title: 'Member Since',
subtitle: user.createdAt.toDate,
subtitle: 'January 15, 2024',
showArrow: false,
),
],

View File

@ -1,15 +1,12 @@
import 'package:flutter/material.dart';
import 'dart:math' as math;
import '../../../../common/extension/extension.dart';
import '../../../../common/painter/wave_painter.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/auth/auth.dart';
import '../../../components/spacer/spacer.dart';
class ProfileHeader extends StatefulWidget {
final User user;
const ProfileHeader({super.key, required this.user});
const ProfileHeader({super.key});
@override
State<ProfileHeader> createState() => _ProfileHeaderState();
@ -350,7 +347,7 @@ class _ProfileHeaderState extends State<ProfileHeader>
child: Column(
children: [
Text(
widget.user.name,
'John Doe',
style: AppStyle.h5.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textWhite,
@ -411,7 +408,7 @@ class _ProfileHeaderState extends State<ProfileHeader>
),
const SpaceHeight(6),
Text(
widget.user.role.toTitleCase,
'Business Owner',
style: AppStyle.md.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w600,

File diff suppressed because it is too large Load Diff

View File

@ -48,8 +48,5 @@ class AppRouter extends RootStackRouter {
// Finance page
AutoRoute(page: FinanceRoute.page),
// Error
AutoRoute(page: ErrorRoute.page),
];
}

View File

@ -10,51 +10,48 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:apskel_owner_flutter/presentation/pages/auth/login/login_page.dart'
as _i8;
as _i7;
import 'package:apskel_owner_flutter/presentation/pages/customer/customer_page.dart'
as _i1;
import 'package:apskel_owner_flutter/presentation/pages/error/error_page.dart'
as _i3;
import 'package:apskel_owner_flutter/presentation/pages/finance/finance_page.dart'
as _i4;
as _i3;
import 'package:apskel_owner_flutter/presentation/pages/form/daily_task_form_page.dart'
as _i2;
import 'package:apskel_owner_flutter/presentation/pages/home/home_page.dart'
as _i5;
as _i4;
import 'package:apskel_owner_flutter/presentation/pages/inventory/inventory_page.dart'
as _i6;
as _i5;
import 'package:apskel_owner_flutter/presentation/pages/language/language_page.dart'
as _i7;
as _i6;
import 'package:apskel_owner_flutter/presentation/pages/main/main_page.dart'
as _i9;
as _i8;
import 'package:apskel_owner_flutter/presentation/pages/product/product_page.dart'
as _i10;
as _i9;
import 'package:apskel_owner_flutter/presentation/pages/profile/profile_page.dart'
as _i11;
as _i10;
import 'package:apskel_owner_flutter/presentation/pages/purchase/purchase_page.dart'
as _i12;
as _i11;
import 'package:apskel_owner_flutter/presentation/pages/report/report_page.dart'
as _i13;
as _i12;
import 'package:apskel_owner_flutter/presentation/pages/sales/sales_page.dart'
as _i14;
as _i13;
import 'package:apskel_owner_flutter/presentation/pages/schedule/schedule_page.dart'
as _i15;
as _i14;
import 'package:apskel_owner_flutter/presentation/pages/splash/splash_page.dart'
as _i16;
as _i15;
import 'package:apskel_owner_flutter/presentation/pages/transaction/transaction_page.dart'
as _i17;
import 'package:auto_route/auto_route.dart' as _i18;
import 'package:flutter/material.dart' as _i19;
as _i16;
import 'package:auto_route/auto_route.dart' as _i17;
/// generated route for
/// [_i1.CustomerPage]
class CustomerRoute extends _i18.PageRouteInfo<void> {
const CustomerRoute({List<_i18.PageRouteInfo>? children})
class CustomerRoute extends _i17.PageRouteInfo<void> {
const CustomerRoute({List<_i17.PageRouteInfo>? children})
: super(CustomerRoute.name, initialChildren: children);
static const String name = 'CustomerRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i1.CustomerPage();
@ -64,13 +61,13 @@ class CustomerRoute extends _i18.PageRouteInfo<void> {
/// generated route for
/// [_i2.DailyTasksFormPage]
class DailyTasksFormRoute extends _i18.PageRouteInfo<void> {
const DailyTasksFormRoute({List<_i18.PageRouteInfo>? children})
class DailyTasksFormRoute extends _i17.PageRouteInfo<void> {
const DailyTasksFormRoute({List<_i17.PageRouteInfo>? children})
: super(DailyTasksFormRoute.name, initialChildren: children);
static const String name = 'DailyTasksFormRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i2.DailyTasksFormPage();
@ -79,303 +76,225 @@ class DailyTasksFormRoute extends _i18.PageRouteInfo<void> {
}
/// generated route for
/// [_i3.ErrorPage]
class ErrorRoute extends _i18.PageRouteInfo<ErrorRouteArgs> {
ErrorRoute({
_i19.Key? key,
String? title,
String? message,
_i19.VoidCallback? onRetry,
_i19.VoidCallback? onBack,
String? errorCode,
_i19.IconData? errorIcon,
List<_i18.PageRouteInfo>? children,
}) : super(
ErrorRoute.name,
args: ErrorRouteArgs(
key: key,
title: title,
message: message,
onRetry: onRetry,
onBack: onBack,
errorCode: errorCode,
errorIcon: errorIcon,
),
initialChildren: children,
);
static const String name = 'ErrorRoute';
static _i18.PageInfo page = _i18.PageInfo(
name,
builder: (data) {
final args = data.argsAs<ErrorRouteArgs>(
orElse: () => const ErrorRouteArgs(),
);
return _i3.ErrorPage(
key: args.key,
title: args.title,
message: args.message,
onRetry: args.onRetry,
onBack: args.onBack,
errorCode: args.errorCode,
errorIcon: args.errorIcon,
);
},
);
}
class ErrorRouteArgs {
const ErrorRouteArgs({
this.key,
this.title,
this.message,
this.onRetry,
this.onBack,
this.errorCode,
this.errorIcon,
});
final _i19.Key? key;
final String? title;
final String? message;
final _i19.VoidCallback? onRetry;
final _i19.VoidCallback? onBack;
final String? errorCode;
final _i19.IconData? errorIcon;
@override
String toString() {
return 'ErrorRouteArgs{key: $key, title: $title, message: $message, onRetry: $onRetry, onBack: $onBack, errorCode: $errorCode, errorIcon: $errorIcon}';
}
}
/// generated route for
/// [_i4.FinancePage]
class FinanceRoute extends _i18.PageRouteInfo<void> {
const FinanceRoute({List<_i18.PageRouteInfo>? children})
/// [_i3.FinancePage]
class FinanceRoute extends _i17.PageRouteInfo<void> {
const FinanceRoute({List<_i17.PageRouteInfo>? children})
: super(FinanceRoute.name, initialChildren: children);
static const String name = 'FinanceRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return _i18.WrappedRoute(child: const _i4.FinancePage());
return const _i3.FinancePage();
},
);
}
/// generated route for
/// [_i5.HomePage]
class HomeRoute extends _i18.PageRouteInfo<void> {
const HomeRoute({List<_i18.PageRouteInfo>? children})
/// [_i4.HomePage]
class HomeRoute extends _i17.PageRouteInfo<void> {
const HomeRoute({List<_i17.PageRouteInfo>? children})
: super(HomeRoute.name, initialChildren: children);
static const String name = 'HomeRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i5.HomePage();
return const _i4.HomePage();
},
);
}
/// generated route for
/// [_i6.InventoryPage]
class InventoryRoute extends _i18.PageRouteInfo<void> {
const InventoryRoute({List<_i18.PageRouteInfo>? children})
/// [_i5.InventoryPage]
class InventoryRoute extends _i17.PageRouteInfo<void> {
const InventoryRoute({List<_i17.PageRouteInfo>? children})
: super(InventoryRoute.name, initialChildren: children);
static const String name = 'InventoryRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i6.InventoryPage();
return const _i5.InventoryPage();
},
);
}
/// generated route for
/// [_i7.LanguagePage]
class LanguageRoute extends _i18.PageRouteInfo<void> {
const LanguageRoute({List<_i18.PageRouteInfo>? children})
/// [_i6.LanguagePage]
class LanguageRoute extends _i17.PageRouteInfo<void> {
const LanguageRoute({List<_i17.PageRouteInfo>? children})
: super(LanguageRoute.name, initialChildren: children);
static const String name = 'LanguageRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i7.LanguagePage();
return const _i6.LanguagePage();
},
);
}
/// generated route for
/// [_i8.LoginPage]
class LoginRoute extends _i18.PageRouteInfo<void> {
const LoginRoute({List<_i18.PageRouteInfo>? children})
/// [_i7.LoginPage]
class LoginRoute extends _i17.PageRouteInfo<void> {
const LoginRoute({List<_i17.PageRouteInfo>? children})
: super(LoginRoute.name, initialChildren: children);
static const String name = 'LoginRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return _i18.WrappedRoute(child: const _i8.LoginPage());
return _i17.WrappedRoute(child: const _i7.LoginPage());
},
);
}
/// generated route for
/// [_i9.MainPage]
class MainRoute extends _i18.PageRouteInfo<void> {
const MainRoute({List<_i18.PageRouteInfo>? children})
/// [_i8.MainPage]
class MainRoute extends _i17.PageRouteInfo<void> {
const MainRoute({List<_i17.PageRouteInfo>? children})
: super(MainRoute.name, initialChildren: children);
static const String name = 'MainRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i9.MainPage();
return const _i8.MainPage();
},
);
}
/// generated route for
/// [_i10.ProductPage]
class ProductRoute extends _i18.PageRouteInfo<void> {
const ProductRoute({List<_i18.PageRouteInfo>? children})
/// [_i9.ProductPage]
class ProductRoute extends _i17.PageRouteInfo<void> {
const ProductRoute({List<_i17.PageRouteInfo>? children})
: super(ProductRoute.name, initialChildren: children);
static const String name = 'ProductRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return _i18.WrappedRoute(child: const _i10.ProductPage());
return const _i9.ProductPage();
},
);
}
/// generated route for
/// [_i11.ProfilePage]
class ProfileRoute extends _i18.PageRouteInfo<void> {
const ProfileRoute({List<_i18.PageRouteInfo>? children})
/// [_i10.ProfilePage]
class ProfileRoute extends _i17.PageRouteInfo<void> {
const ProfileRoute({List<_i17.PageRouteInfo>? children})
: super(ProfileRoute.name, initialChildren: children);
static const String name = 'ProfileRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return _i18.WrappedRoute(child: const _i11.ProfilePage());
return const _i10.ProfilePage();
},
);
}
/// generated route for
/// [_i12.PurchasePage]
class PurchaseRoute extends _i18.PageRouteInfo<void> {
const PurchaseRoute({List<_i18.PageRouteInfo>? children})
/// [_i11.PurchasePage]
class PurchaseRoute extends _i17.PageRouteInfo<void> {
const PurchaseRoute({List<_i17.PageRouteInfo>? children})
: super(PurchaseRoute.name, initialChildren: children);
static const String name = 'PurchaseRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i12.PurchasePage();
return const _i11.PurchasePage();
},
);
}
/// generated route for
/// [_i13.ReportPage]
class ReportRoute extends _i18.PageRouteInfo<void> {
const ReportRoute({List<_i18.PageRouteInfo>? children})
/// [_i12.ReportPage]
class ReportRoute extends _i17.PageRouteInfo<void> {
const ReportRoute({List<_i17.PageRouteInfo>? children})
: super(ReportRoute.name, initialChildren: children);
static const String name = 'ReportRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i13.ReportPage();
return const _i12.ReportPage();
},
);
}
/// generated route for
/// [_i14.SalesPage]
class SalesRoute extends _i18.PageRouteInfo<void> {
const SalesRoute({List<_i18.PageRouteInfo>? children})
/// [_i13.SalesPage]
class SalesRoute extends _i17.PageRouteInfo<void> {
const SalesRoute({List<_i17.PageRouteInfo>? children})
: super(SalesRoute.name, initialChildren: children);
static const String name = 'SalesRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return _i18.WrappedRoute(child: const _i14.SalesPage());
return const _i13.SalesPage();
},
);
}
/// generated route for
/// [_i15.SchedulePage]
class ScheduleRoute extends _i18.PageRouteInfo<void> {
const ScheduleRoute({List<_i18.PageRouteInfo>? children})
/// [_i14.SchedulePage]
class ScheduleRoute extends _i17.PageRouteInfo<void> {
const ScheduleRoute({List<_i17.PageRouteInfo>? children})
: super(ScheduleRoute.name, initialChildren: children);
static const String name = 'ScheduleRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i15.SchedulePage();
return const _i14.SchedulePage();
},
);
}
/// generated route for
/// [_i16.SplashPage]
class SplashRoute extends _i18.PageRouteInfo<void> {
const SplashRoute({List<_i18.PageRouteInfo>? children})
/// [_i15.SplashPage]
class SplashRoute extends _i17.PageRouteInfo<void> {
const SplashRoute({List<_i17.PageRouteInfo>? children})
: super(SplashRoute.name, initialChildren: children);
static const String name = 'SplashRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i16.SplashPage();
return const _i15.SplashPage();
},
);
}
/// generated route for
/// [_i17.TransactionPage]
class TransactionRoute extends _i18.PageRouteInfo<void> {
const TransactionRoute({List<_i18.PageRouteInfo>? children})
/// [_i16.TransactionPage]
class TransactionRoute extends _i17.PageRouteInfo<void> {
const TransactionRoute({List<_i17.PageRouteInfo>? children})
: super(TransactionRoute.name, initialChildren: children);
static const String name = 'TransactionRoute';
static _i18.PageInfo page = _i18.PageInfo(
static _i17.PageInfo page = _i17.PageInfo(
name,
builder: (data) {
return const _i17.TransactionPage();
return const _i16.TransactionPage();
},
);
}

View File

@ -10,7 +10,6 @@ import file_selector_macos
import package_info_plus
import path_provider_foundation
import shared_preferences_foundation
import sqflite_darwin
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
@ -18,5 +17,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
}

View File

@ -161,30 +161,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.11.1"
cached_network_image:
dependency: "direct main"
description:
name: cached_network_image
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
characters:
dependency: transitive
description:
@ -446,14 +422,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "9.1.1"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flutter_gen_core:
dependency: transitive
description:
@ -845,14 +813,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.0"
octo_image:
dependency: transitive
description:
name: octo_image
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
package_config:
dependency: transitive
description:
@ -1013,14 +973,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.1.0"
rxdart:
dependency: transitive
description:
name: rxdart
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.dev"
source: hosted
version: "0.28.0"
shared_preferences:
dependency: "direct main"
description:
@ -1093,14 +1045,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.0"
shimmer:
dependency: "direct main"
description:
name: shimmer
sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
simple_gesture_detector:
dependency: transitive
description:
@ -1138,54 +1082,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
sqflite:
dependency: transitive
description:
name: sqflite
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
url: "https://pub.dev"
source: hosted
version: "2.4.2"
sqflite_android:
dependency: transitive
description:
name: sqflite_android
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
url: "https://pub.dev"
source: hosted
version: "2.5.6"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
sqflite_platform_interface:
dependency: transitive
description:
name: sqflite_platform_interface
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
stack_trace:
dependency: transitive
description:
@ -1218,14 +1114,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
url: "https://pub.dev"
source: hosted
version: "3.4.0"
table_calendar:
dependency: "direct main"
description:
@ -1274,14 +1162,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
uuid:
dependency: transitive
description:
name: uuid
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev"
source: hosted
version: "4.5.1"
vector_graphics:
dependency: transitive
description:

View File

@ -40,8 +40,6 @@ dependencies:
table_calendar: ^3.2.0
package_info_plus: ^8.3.1
loader_overlay: ^5.0.0
shimmer: ^3.0.0
cached_network_image: ^3.4.1
dev_dependencies:
flutter_test: