Compare commits

...

5 Commits

Author SHA1 Message Date
efrilm
b4d2d859eb feat: order detail 2025-08-18 15:30:34 +07:00
efrilm
c367bd2cd9 feat: change structure order 2025-08-18 14:26:56 +07:00
efrilm
d3f2cb300c feat: order 2025-08-18 14:24:15 +07:00
efrilm
62eb15b27f feat: change name transaction to order 2025-08-18 13:33:45 +07:00
efrilm
b8055c8eab feat: change structure 2025-08-18 13:07:48 +07:00
31 changed files with 8180 additions and 610 deletions

View File

@ -0,0 +1,90 @@
import 'package:dartz/dartz.dart' hide Order;
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart' hide Order;
import '../../../domain/order/order.dart';
part 'order_loader_event.dart';
part 'order_loader_state.dart';
part 'order_loader_bloc.freezed.dart';
@injectable
class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
final IOrderRepository _repository;
OrderLoaderBloc(this._repository) : super(OrderLoaderState.initial()) {
on<OrderLoaderEvent>(_onOrderLoaderEvent);
}
Future<void> _onOrderLoaderEvent(
OrderLoaderEvent event,
Emitter<OrderLoaderState> emit,
) {
return event.map(
statusChanged: (e) async {
emit(state.copyWith(status: e.status));
},
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<OrderLoaderState> _mapFetchedToState(
OrderLoaderState state, {
bool isRefresh = false,
}) async {
state = state.copyWith(isFetching: false);
if (state.hasReachedMax && state.orders.isNotEmpty && !isRefresh) {
return state;
}
if (isRefresh) {
state = state.copyWith(
page: 1,
failureOptionOrder: none(),
hasReachedMax: false,
orders: [],
);
}
final failureOrOrder = await _repository.get(
status: state.status,
page: state.page,
search: state.search,
);
state = failureOrOrder.fold(
(f) {
if (state.orders.isNotEmpty) {
return state.copyWith(hasReachedMax: true);
}
return state.copyWith(failureOptionOrder: optionOf(f));
},
(orders) {
return state.copyWith(
orders: List.from(state.orders)..addAll(orders),
failureOptionOrder: none(),
page: state.page + 1,
hasReachedMax: orders.length < 10,
);
},
);
return state;
}
}

View File

@ -0,0 +1,815 @@
// 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 'order_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 _$OrderLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged,
required TResult Function(bool isRefresh) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $OrderLoaderEventCopyWith<$Res> {
factory $OrderLoaderEventCopyWith(
OrderLoaderEvent value,
$Res Function(OrderLoaderEvent) then,
) = _$OrderLoaderEventCopyWithImpl<$Res, OrderLoaderEvent>;
}
/// @nodoc
class _$OrderLoaderEventCopyWithImpl<$Res, $Val extends OrderLoaderEvent>
implements $OrderLoaderEventCopyWith<$Res> {
_$OrderLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$StatusChangedImplCopyWith<$Res> {
factory _$$StatusChangedImplCopyWith(
_$StatusChangedImpl value,
$Res Function(_$StatusChangedImpl) then,
) = __$$StatusChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({String status});
}
/// @nodoc
class __$$StatusChangedImplCopyWithImpl<$Res>
extends _$OrderLoaderEventCopyWithImpl<$Res, _$StatusChangedImpl>
implements _$$StatusChangedImplCopyWith<$Res> {
__$$StatusChangedImplCopyWithImpl(
_$StatusChangedImpl _value,
$Res Function(_$StatusChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? status = null}) {
return _then(
_$StatusChangedImpl(
null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$StatusChangedImpl implements _StatusChanged {
const _$StatusChangedImpl(this.status);
@override
final String status;
@override
String toString() {
return 'OrderLoaderEvent.statusChanged(status: $status)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$StatusChangedImpl &&
(identical(other.status, status) || other.status == status));
}
@override
int get hashCode => Object.hash(runtimeType, status);
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$StatusChangedImplCopyWith<_$StatusChangedImpl> get copyWith =>
__$$StatusChangedImplCopyWithImpl<_$StatusChangedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return statusChanged(status);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return statusChanged?.call(status);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (statusChanged != null) {
return statusChanged(status);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) {
return statusChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return statusChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (statusChanged != null) {
return statusChanged(this);
}
return orElse();
}
}
abstract class _StatusChanged implements OrderLoaderEvent {
const factory _StatusChanged(final String status) = _$StatusChangedImpl;
String get status;
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$StatusChangedImplCopyWith<_$StatusChangedImpl> 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 _$OrderLoaderEventCopyWithImpl<$Res, _$SearchChangedImpl>
implements _$$SearchChangedImplCopyWith<$Res> {
__$$SearchChangedImplCopyWithImpl(
_$SearchChangedImpl _value,
$Res Function(_$SearchChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of OrderLoaderEvent
/// 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 'OrderLoaderEvent.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 OrderLoaderEvent
/// 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 status) statusChanged,
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 status)? statusChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return searchChanged?.call(search);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status)? statusChanged,
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(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) {
return searchChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return searchChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StatusChanged value)? statusChanged,
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 OrderLoaderEvent {
const factory _SearchChanged(final String search) = _$SearchChangedImpl;
String get search;
/// Create a copy of OrderLoaderEvent
/// 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 _$OrderLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of OrderLoaderEvent
/// 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 'OrderLoaderEvent.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 OrderLoaderEvent
/// 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 status) statusChanged,
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 status)? statusChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return fetched?.call(isRefresh);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String status)? statusChanged,
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(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StatusChanged value)? statusChanged,
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 OrderLoaderEvent {
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
bool get isRefresh;
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$OrderLoaderState {
List<Order> get orders => throw _privateConstructorUsedError;
Option<OrderFailure> get failureOptionOrder =>
throw _privateConstructorUsedError;
String? get status => 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 OrderLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$OrderLoaderStateCopyWith<OrderLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $OrderLoaderStateCopyWith<$Res> {
factory $OrderLoaderStateCopyWith(
OrderLoaderState value,
$Res Function(OrderLoaderState) then,
) = _$OrderLoaderStateCopyWithImpl<$Res, OrderLoaderState>;
@useResult
$Res call({
List<Order> orders,
Option<OrderFailure> failureOptionOrder,
String? status,
String? search,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class _$OrderLoaderStateCopyWithImpl<$Res, $Val extends OrderLoaderState>
implements $OrderLoaderStateCopyWith<$Res> {
_$OrderLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of OrderLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? orders = null,
Object? failureOptionOrder = null,
Object? status = freezed,
Object? search = freezed,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_value.copyWith(
orders: null == orders
? _value.orders
: orders // ignore: cast_nullable_to_non_nullable
as List<Order>,
failureOptionOrder: null == failureOptionOrder
? _value.failureOptionOrder
: failureOptionOrder // ignore: cast_nullable_to_non_nullable
as Option<OrderFailure>,
status: freezed == status
? _value.status
: status // 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 _$$OrderLoaderStateImplCopyWith<$Res>
implements $OrderLoaderStateCopyWith<$Res> {
factory _$$OrderLoaderStateImplCopyWith(
_$OrderLoaderStateImpl value,
$Res Function(_$OrderLoaderStateImpl) then,
) = __$$OrderLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
List<Order> orders,
Option<OrderFailure> failureOptionOrder,
String? status,
String? search,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class __$$OrderLoaderStateImplCopyWithImpl<$Res>
extends _$OrderLoaderStateCopyWithImpl<$Res, _$OrderLoaderStateImpl>
implements _$$OrderLoaderStateImplCopyWith<$Res> {
__$$OrderLoaderStateImplCopyWithImpl(
_$OrderLoaderStateImpl _value,
$Res Function(_$OrderLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of OrderLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? orders = null,
Object? failureOptionOrder = null,
Object? status = freezed,
Object? search = freezed,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_$OrderLoaderStateImpl(
orders: null == orders
? _value._orders
: orders // ignore: cast_nullable_to_non_nullable
as List<Order>,
failureOptionOrder: null == failureOptionOrder
? _value.failureOptionOrder
: failureOptionOrder // ignore: cast_nullable_to_non_nullable
as Option<OrderFailure>,
status: freezed == status
? _value.status
: status // 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 _$OrderLoaderStateImpl implements _OrderLoaderState {
const _$OrderLoaderStateImpl({
required final List<Order> orders,
required this.failureOptionOrder,
this.status,
this.search,
this.isFetching = false,
this.hasReachedMax = false,
this.page = 1,
}) : _orders = orders;
final List<Order> _orders;
@override
List<Order> get orders {
if (_orders is EqualUnmodifiableListView) return _orders;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_orders);
}
@override
final Option<OrderFailure> failureOptionOrder;
@override
final String? status;
@override
final String? search;
@override
@JsonKey()
final bool isFetching;
@override
@JsonKey()
final bool hasReachedMax;
@override
@JsonKey()
final int page;
@override
String toString() {
return 'OrderLoaderState(orders: $orders, failureOptionOrder: $failureOptionOrder, status: $status, search: $search, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$OrderLoaderStateImpl &&
const DeepCollectionEquality().equals(other._orders, _orders) &&
(identical(other.failureOptionOrder, failureOptionOrder) ||
other.failureOptionOrder == failureOptionOrder) &&
(identical(other.status, status) || other.status == status) &&
(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(_orders),
failureOptionOrder,
status,
search,
isFetching,
hasReachedMax,
page,
);
/// Create a copy of OrderLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$OrderLoaderStateImplCopyWith<_$OrderLoaderStateImpl> get copyWith =>
__$$OrderLoaderStateImplCopyWithImpl<_$OrderLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _OrderLoaderState implements OrderLoaderState {
const factory _OrderLoaderState({
required final List<Order> orders,
required final Option<OrderFailure> failureOptionOrder,
final String? status,
final String? search,
final bool isFetching,
final bool hasReachedMax,
final int page,
}) = _$OrderLoaderStateImpl;
@override
List<Order> get orders;
@override
Option<OrderFailure> get failureOptionOrder;
@override
String? get status;
@override
String? get search;
@override
bool get isFetching;
@override
bool get hasReachedMax;
@override
int get page;
/// Create a copy of OrderLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$OrderLoaderStateImplCopyWith<_$OrderLoaderStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,9 @@
part of 'order_loader_bloc.dart';
@freezed
class OrderLoaderEvent with _$OrderLoaderEvent {
const factory OrderLoaderEvent.statusChanged(String status) = _StatusChanged;
const factory OrderLoaderEvent.searchChanged(String search) = _SearchChanged;
const factory OrderLoaderEvent.fetched({@Default(false) bool isRefresh}) =
_Fetched;
}

View File

@ -0,0 +1,17 @@
part of 'order_loader_bloc.dart';
@freezed
class OrderLoaderState with _$OrderLoaderState {
const factory OrderLoaderState({
required List<Order> orders,
required Option<OrderFailure> failureOptionOrder,
String? status,
String? search,
@Default(false) bool isFetching,
@Default(false) bool hasReachedMax,
@Default(1) int page,
}) = _OrderLoaderState;
factory OrderLoaderState.initial() =>
OrderLoaderState(orders: [], failureOptionOrder: none());
}

View File

@ -24,4 +24,7 @@ class ApiPath {
// Customer // Customer
static const String customer = '/api/v1/customers'; static const String customer = '/api/v1/customers';
// Order
static const String order = '/api/v1/orders';
} }

View File

@ -0,0 +1,161 @@
part of '../order.dart';
@freezed
class Order with _$Order {
const factory Order({
required String id,
required String orderNumber,
required String outletId,
required String userId,
required String tableNumber,
required String orderType,
required String status,
required int subtotal,
required int taxAmount,
required int discountAmount,
required int totalAmount,
required int totalCost,
required int remainingAmount,
required String paymentStatus,
required int refundAmount,
required bool isVoid,
required bool isRefund,
required String notes,
required Map<String, dynamic> metadata,
required String createdAt,
required String updatedAt,
required List<OrderItem> orderItems,
required List<OrderPayment> payments,
required int totalPaid,
required int paymentCount,
required String splitType,
}) = _Order;
factory Order.empty() => Order(
id: '',
orderNumber: '',
outletId: '',
userId: '',
tableNumber: '',
orderType: '',
status: '',
subtotal: 0,
taxAmount: 0,
discountAmount: 0,
totalAmount: 0,
totalCost: 0,
remainingAmount: 0,
paymentStatus: '',
refundAmount: 0,
isVoid: false,
isRefund: false,
notes: '',
metadata: {},
createdAt: '',
updatedAt: '',
orderItems: [],
payments: [],
totalPaid: 0,
paymentCount: 0,
splitType: '',
);
}
@freezed
class OrderItem with _$OrderItem {
const factory OrderItem({
required String id,
required String orderId,
required String productId,
required String productName,
required int quantity,
required int price,
required int subtotal,
required int discountAmount,
required int total,
required int cost,
required Map<String, dynamic> metadata,
required String createdAt,
required String updatedAt,
}) = _OrderItem;
factory OrderItem.empty() => OrderItem(
id: '',
orderId: '',
productId: '',
productName: '',
quantity: 0,
price: 0,
subtotal: 0,
discountAmount: 0,
total: 0,
cost: 0,
metadata: {},
createdAt: '',
updatedAt: '',
);
}
@freezed
class OrderPayment with _$OrderPayment {
const factory OrderPayment({
required String id,
required String orderId,
required String paymentMethodId,
required String paymentMethodName,
required String paymentMethodType,
required int amount,
required String status,
required int splitNumber,
required int splitTotal,
required String splitType,
required String splitDescription,
required int refundAmount,
required Map<String, dynamic> metadata,
required String createdAt,
required String updatedAt,
required List<PaymentOrderItem> paymentOrderItems,
}) = _OrderPayment;
factory OrderPayment.empty() => OrderPayment(
id: '',
orderId: '',
paymentMethodId: '',
paymentMethodName: '',
paymentMethodType: '',
amount: 0,
status: '',
splitNumber: 0,
splitTotal: 0,
splitType: '',
splitDescription: '',
refundAmount: 0,
metadata: {},
createdAt: '',
updatedAt: '',
paymentOrderItems: [],
);
}
@freezed
class PaymentOrderItem with _$PaymentOrderItem {
const factory PaymentOrderItem({
required String id,
required String orderPaymentId,
required String orderItemId,
required int amount,
required int refundAmount,
required String createdAt,
required String updatedAt,
}) = _PaymentOrderItem;
factory PaymentOrderItem.empty() => PaymentOrderItem(
id: '',
orderPaymentId: '',
orderItemId: '',
amount: 0,
refundAmount: 0,
createdAt: '',
updatedAt: '',
);
}

View File

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

View File

@ -0,0 +1,10 @@
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'order.freezed.dart';
part 'entities/order_entity.dart';
part 'failures/order_failure.dart';
part 'repositories/i_order_repository.dart';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
part of '../order.dart';
abstract class IOrderRepository {
Future<Either<OrderFailure, List<Order>>> get({
int page = 1,
int limit = 10,
String? status,
String? search,
});
}

View File

@ -0,0 +1,57 @@
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/order/order.dart';
import '../order_dtos.dart';
@injectable
class OrderRemoteDataProvider {
final ApiClient _apiClient;
final String _logName = 'OrderRemoteDataProvider';
OrderRemoteDataProvider(this._apiClient);
Future<DC<OrderFailure, List<OrderDto>>> fetch({
int page = 1,
int limit = 10,
String? status,
String? search,
}) async {
try {
Map<String, dynamic> params = {'page': page, 'limit': limit};
if (status != null && status.isNotEmpty) {
params['status'] = status;
}
if (search != null && search.isNotEmpty) {
params['search'] = search;
}
final response = await _apiClient.get(
ApiPath.order,
params: params,
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(OrderFailure.empty());
}
final dto = (response.data['data']['orders'] as List)
.map((item) => OrderDto.fromJson(item))
.toList();
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchOrderError', name: _logName, error: e, stackTrace: s);
return DC.error(OrderFailure.serverError(e));
}
}
}

View File

@ -0,0 +1,183 @@
part of '../order_dtos.dart';
@freezed
class OrderDto with _$OrderDto {
const OrderDto._();
const factory OrderDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'order_number') String? orderNumber,
@JsonKey(name: 'outlet_id') String? outletId,
@JsonKey(name: 'user_id') String? userId,
@JsonKey(name: 'table_number') String? tableNumber,
@JsonKey(name: 'order_type') String? orderType,
@JsonKey(name: 'status') String? status,
@JsonKey(name: 'subtotal') int? subtotal,
@JsonKey(name: 'tax_amount') int? taxAmount,
@JsonKey(name: 'discount_amount') int? discountAmount,
@JsonKey(name: 'total_amount') int? totalAmount,
@JsonKey(name: 'total_cost') int? totalCost,
@JsonKey(name: 'remaining_amount') int? remainingAmount,
@JsonKey(name: 'payment_status') String? paymentStatus,
@JsonKey(name: 'refund_amount') int? refundAmount,
@JsonKey(name: 'is_void') bool? isVoid,
@JsonKey(name: 'is_refund') bool? isRefund,
@JsonKey(name: 'notes') String? notes,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
@JsonKey(name: 'order_items') List<OrderItemDto>? orderItems,
@JsonKey(name: 'payments') List<OrderPaymentDto>? payments,
@JsonKey(name: 'total_paid') int? totalPaid,
@JsonKey(name: 'payment_count') int? paymentCount,
@JsonKey(name: 'split_type') String? splitType,
}) = _OrderDto;
factory OrderDto.fromJson(Map<String, dynamic> json) =>
_$OrderDtoFromJson(json);
Order toDomain() => Order(
id: id ?? '',
orderNumber: orderNumber ?? '',
outletId: outletId ?? '',
userId: userId ?? '',
tableNumber: tableNumber ?? '',
orderType: orderType ?? '',
status: status ?? '',
subtotal: subtotal ?? 0,
taxAmount: taxAmount ?? 0,
discountAmount: discountAmount ?? 0,
totalAmount: totalAmount ?? 0,
totalCost: totalCost ?? 0,
remainingAmount: remainingAmount ?? 0,
paymentStatus: paymentStatus ?? '',
refundAmount: refundAmount ?? 0,
isVoid: isVoid ?? false,
isRefund: isRefund ?? false,
notes: notes ?? '',
metadata: metadata ?? {},
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
orderItems: orderItems?.map((e) => e.toDomain()).toList() ?? [],
payments: payments?.map((e) => e.toDomain()).toList() ?? [],
totalPaid: totalPaid ?? 0,
paymentCount: paymentCount ?? 0,
splitType: splitType ?? '',
);
}
@freezed
class OrderItemDto with _$OrderItemDto {
const OrderItemDto._();
const factory OrderItemDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'order_id') String? orderId,
@JsonKey(name: 'product_id') String? productId,
@JsonKey(name: 'product_name') String? productName,
@JsonKey(name: 'quantity') int? quantity,
@JsonKey(name: 'price') int? price,
@JsonKey(name: 'subtotal') int? subtotal,
@JsonKey(name: 'discount_amount') int? discountAmount,
@JsonKey(name: 'total') int? total,
@JsonKey(name: 'cost') int? cost,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
}) = _OrderItemDto;
factory OrderItemDto.fromJson(Map<String, dynamic> json) =>
_$OrderItemDtoFromJson(json);
OrderItem toDomain() => OrderItem(
id: id ?? '',
orderId: orderId ?? '',
productId: productId ?? '',
productName: productName ?? '',
quantity: quantity ?? 0,
price: price ?? 0,
subtotal: subtotal ?? 0,
discountAmount: discountAmount ?? 0,
total: total ?? 0,
cost: cost ?? 0,
metadata: metadata ?? {},
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
);
}
@freezed
class OrderPaymentDto with _$OrderPaymentDto {
const OrderPaymentDto._();
const factory OrderPaymentDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'order_id') String? orderId,
@JsonKey(name: 'payment_method_id') String? paymentMethodId,
@JsonKey(name: 'payment_method_name') String? paymentMethodName,
@JsonKey(name: 'payment_method_type') String? paymentMethodType,
@JsonKey(name: 'amount') int? amount,
@JsonKey(name: 'status') String? status,
@JsonKey(name: 'split_number') int? splitNumber,
@JsonKey(name: 'split_total') int? splitTotal,
@JsonKey(name: 'split_type') String? splitType,
@JsonKey(name: 'split_description') String? splitDescription,
@JsonKey(name: 'refund_amount') int? refundAmount,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
@JsonKey(name: 'payment_order_items')
List<PaymentOrderItemDto>? paymentOrderItems,
}) = _OrderPaymentDto;
factory OrderPaymentDto.fromJson(Map<String, dynamic> json) =>
_$OrderPaymentDtoFromJson(json);
OrderPayment toDomain() => OrderPayment(
id: id ?? '',
orderId: orderId ?? '',
paymentMethodId: paymentMethodId ?? '',
paymentMethodName: paymentMethodName ?? '',
paymentMethodType: paymentMethodType ?? '',
amount: amount ?? 0,
status: status ?? '',
splitNumber: splitNumber ?? 0,
splitTotal: splitTotal ?? 0,
splitType: splitType ?? '',
splitDescription: splitDescription ?? '',
refundAmount: refundAmount ?? 0,
metadata: metadata ?? {},
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
paymentOrderItems:
paymentOrderItems?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class PaymentOrderItemDto with _$PaymentOrderItemDto {
const PaymentOrderItemDto._();
const factory PaymentOrderItemDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'order_payment_id') String? orderPaymentId,
@JsonKey(name: 'order_item_id') String? orderItemId,
@JsonKey(name: 'amount') int? amount,
@JsonKey(name: 'refund_amount') int? refundAmount,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
}) = _PaymentOrderItemDto;
factory PaymentOrderItemDto.fromJson(Map<String, dynamic> json) =>
_$PaymentOrderItemDtoFromJson(json);
PaymentOrderItem toDomain() => PaymentOrderItem(
id: id ?? '',
orderPaymentId: orderPaymentId ?? '',
orderItemId: orderItemId ?? '',
amount: amount ?? 0,
refundAmount: refundAmount ?? 0,
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
);
}

View File

@ -0,0 +1,8 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/order/order.dart';
part 'order_dtos.freezed.dart';
part 'order_dtos.g.dart';
part 'dto/order_dto.dart';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'order_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$OrderDtoImpl _$$OrderDtoImplFromJson(Map<String, dynamic> json) =>
_$OrderDtoImpl(
id: json['id'] as String?,
orderNumber: json['order_number'] as String?,
outletId: json['outlet_id'] as String?,
userId: json['user_id'] as String?,
tableNumber: json['table_number'] as String?,
orderType: json['order_type'] as String?,
status: json['status'] as String?,
subtotal: (json['subtotal'] as num?)?.toInt(),
taxAmount: (json['tax_amount'] as num?)?.toInt(),
discountAmount: (json['discount_amount'] as num?)?.toInt(),
totalAmount: (json['total_amount'] as num?)?.toInt(),
totalCost: (json['total_cost'] as num?)?.toInt(),
remainingAmount: (json['remaining_amount'] as num?)?.toInt(),
paymentStatus: json['payment_status'] as String?,
refundAmount: (json['refund_amount'] as num?)?.toInt(),
isVoid: json['is_void'] as bool?,
isRefund: json['is_refund'] as bool?,
notes: json['notes'] as String?,
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
orderItems: (json['order_items'] as List<dynamic>?)
?.map((e) => OrderItemDto.fromJson(e as Map<String, dynamic>))
.toList(),
payments: (json['payments'] as List<dynamic>?)
?.map((e) => OrderPaymentDto.fromJson(e as Map<String, dynamic>))
.toList(),
totalPaid: (json['total_paid'] as num?)?.toInt(),
paymentCount: (json['payment_count'] as num?)?.toInt(),
splitType: json['split_type'] as String?,
);
Map<String, dynamic> _$$OrderDtoImplToJson(_$OrderDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'order_number': instance.orderNumber,
'outlet_id': instance.outletId,
'user_id': instance.userId,
'table_number': instance.tableNumber,
'order_type': instance.orderType,
'status': instance.status,
'subtotal': instance.subtotal,
'tax_amount': instance.taxAmount,
'discount_amount': instance.discountAmount,
'total_amount': instance.totalAmount,
'total_cost': instance.totalCost,
'remaining_amount': instance.remainingAmount,
'payment_status': instance.paymentStatus,
'refund_amount': instance.refundAmount,
'is_void': instance.isVoid,
'is_refund': instance.isRefund,
'notes': instance.notes,
'metadata': instance.metadata,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
'order_items': instance.orderItems,
'payments': instance.payments,
'total_paid': instance.totalPaid,
'payment_count': instance.paymentCount,
'split_type': instance.splitType,
};
_$OrderItemDtoImpl _$$OrderItemDtoImplFromJson(Map<String, dynamic> json) =>
_$OrderItemDtoImpl(
id: json['id'] as String?,
orderId: json['order_id'] as String?,
productId: json['product_id'] as String?,
productName: json['product_name'] as String?,
quantity: (json['quantity'] as num?)?.toInt(),
price: (json['price'] as num?)?.toInt(),
subtotal: (json['subtotal'] as num?)?.toInt(),
discountAmount: (json['discount_amount'] as num?)?.toInt(),
total: (json['total'] as num?)?.toInt(),
cost: (json['cost'] as num?)?.toInt(),
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$OrderItemDtoImplToJson(_$OrderItemDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'order_id': instance.orderId,
'product_id': instance.productId,
'product_name': instance.productName,
'quantity': instance.quantity,
'price': instance.price,
'subtotal': instance.subtotal,
'discount_amount': instance.discountAmount,
'total': instance.total,
'cost': instance.cost,
'metadata': instance.metadata,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
_$OrderPaymentDtoImpl _$$OrderPaymentDtoImplFromJson(
Map<String, dynamic> json,
) => _$OrderPaymentDtoImpl(
id: json['id'] as String?,
orderId: json['order_id'] as String?,
paymentMethodId: json['payment_method_id'] as String?,
paymentMethodName: json['payment_method_name'] as String?,
paymentMethodType: json['payment_method_type'] as String?,
amount: (json['amount'] as num?)?.toInt(),
status: json['status'] as String?,
splitNumber: (json['split_number'] as num?)?.toInt(),
splitTotal: (json['split_total'] as num?)?.toInt(),
splitType: json['split_type'] as String?,
splitDescription: json['split_description'] as String?,
refundAmount: (json['refund_amount'] as num?)?.toInt(),
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
paymentOrderItems: (json['payment_order_items'] as List<dynamic>?)
?.map((e) => PaymentOrderItemDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$OrderPaymentDtoImplToJson(
_$OrderPaymentDtoImpl instance,
) => <String, dynamic>{
'id': instance.id,
'order_id': instance.orderId,
'payment_method_id': instance.paymentMethodId,
'payment_method_name': instance.paymentMethodName,
'payment_method_type': instance.paymentMethodType,
'amount': instance.amount,
'status': instance.status,
'split_number': instance.splitNumber,
'split_total': instance.splitTotal,
'split_type': instance.splitType,
'split_description': instance.splitDescription,
'refund_amount': instance.refundAmount,
'metadata': instance.metadata,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
'payment_order_items': instance.paymentOrderItems,
};
_$PaymentOrderItemDtoImpl _$$PaymentOrderItemDtoImplFromJson(
Map<String, dynamic> json,
) => _$PaymentOrderItemDtoImpl(
id: json['id'] as String?,
orderPaymentId: json['order_payment_id'] as String?,
orderItemId: json['order_item_id'] as String?,
amount: (json['amount'] as num?)?.toInt(),
refundAmount: (json['refund_amount'] as num?)?.toInt(),
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$PaymentOrderItemDtoImplToJson(
_$PaymentOrderItemDtoImpl instance,
) => <String, dynamic>{
'id': instance.id,
'order_payment_id': instance.orderPaymentId,
'order_item_id': instance.orderItemId,
'amount': instance.amount,
'refund_amount': instance.refundAmount,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};

View File

@ -0,0 +1,43 @@
import 'dart:developer';
import 'package:dartz/dartz.dart' hide Order;
import 'package:injectable/injectable.dart' hide Order;
import '../../../domain/order/order.dart';
import '../datasource/remote_data_provider.dart';
@Injectable(as: IOrderRepository)
class OrderRepository implements IOrderRepository {
final OrderRemoteDataProvider _dataProvider;
final String _logName = 'OrderRepository';
OrderRepository(this._dataProvider);
@override
Future<Either<OrderFailure, List<Order>>> get({
int page = 1,
int limit = 20,
String? status,
String? search,
}) async {
try {
final result = await _dataProvider.fetch(
page: page,
limit: limit,
status: status,
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('getOrderError', name: _logName, error: e, stackTrace: s);
return left(const OrderFailure.unexpectedError());
}
}
}

View File

@ -34,6 +34,8 @@ import 'package:apskel_owner_flutter/application/customer/customer_loader/custom
as _i972; as _i972;
import 'package:apskel_owner_flutter/application/language/language_bloc.dart' import 'package:apskel_owner_flutter/application/language/language_bloc.dart'
as _i455; as _i455;
import 'package:apskel_owner_flutter/application/order/order_loader/order_loader_bloc.dart'
as _i1058;
import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart' import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart'
as _i458; as _i458;
import 'package:apskel_owner_flutter/common/api/api_client.dart' as _i115; import 'package:apskel_owner_flutter/common/api/api_client.dart' as _i115;
@ -50,6 +52,7 @@ import 'package:apskel_owner_flutter/domain/analytic/repositories/i_analytic_rep
import 'package:apskel_owner_flutter/domain/auth/auth.dart' as _i49; 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/category/category.dart' as _i1020;
import 'package:apskel_owner_flutter/domain/customer/customer.dart' as _i48; import 'package:apskel_owner_flutter/domain/customer/customer.dart' as _i48;
import 'package:apskel_owner_flutter/domain/order/order.dart' as _i219;
import 'package:apskel_owner_flutter/domain/product/product.dart' as _i419; 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/env.dart' as _i6;
import 'package:apskel_owner_flutter/infrastructure/analytic/datasource/remote_data_provider.dart' import 'package:apskel_owner_flutter/infrastructure/analytic/datasource/remote_data_provider.dart'
@ -70,6 +73,10 @@ import 'package:apskel_owner_flutter/infrastructure/customer/datasources/remote_
as _i1006; as _i1006;
import 'package:apskel_owner_flutter/infrastructure/customer/repositories/customer_repository.dart' import 'package:apskel_owner_flutter/infrastructure/customer/repositories/customer_repository.dart'
as _i550; as _i550;
import 'package:apskel_owner_flutter/infrastructure/order/datasource/remote_data_provider.dart'
as _i130;
import 'package:apskel_owner_flutter/infrastructure/order/repositories/order_repository.dart'
as _i641;
import 'package:apskel_owner_flutter/infrastructure/product/datasources/remote_data_provider.dart' import 'package:apskel_owner_flutter/infrastructure/product/datasources/remote_data_provider.dart'
as _i823; as _i823;
import 'package:apskel_owner_flutter/infrastructure/product/repositories/product_repository.dart' import 'package:apskel_owner_flutter/infrastructure/product/repositories/product_repository.dart'
@ -138,9 +145,15 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i1006.CustomerRemoteDataProvider>( gh.factory<_i1006.CustomerRemoteDataProvider>(
() => _i1006.CustomerRemoteDataProvider(gh<_i115.ApiClient>()), () => _i1006.CustomerRemoteDataProvider(gh<_i115.ApiClient>()),
); );
gh.factory<_i130.OrderRemoteDataProvider>(
() => _i130.OrderRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i48.ICustomerRepository>( gh.factory<_i48.ICustomerRepository>(
() => _i550.CustomerRepository(gh<_i1006.CustomerRemoteDataProvider>()), () => _i550.CustomerRepository(gh<_i1006.CustomerRemoteDataProvider>()),
); );
gh.factory<_i219.IOrderRepository>(
() => _i641.OrderRepository(gh<_i130.OrderRemoteDataProvider>()),
);
gh.factory<_i49.IAuthRepository>( gh.factory<_i49.IAuthRepository>(
() => _i1035.AuthRepository( () => _i1035.AuthRepository(
gh<_i991.AuthLocalDataProvider>(), gh<_i991.AuthLocalDataProvider>(),
@ -200,6 +213,9 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i574.LogoutFormBloc>( gh.factory<_i574.LogoutFormBloc>(
() => _i574.LogoutFormBloc(gh<_i49.IAuthRepository>()), () => _i574.LogoutFormBloc(gh<_i49.IAuthRepository>()),
); );
gh.factory<_i1058.OrderLoaderBloc>(
() => _i1058.OrderLoaderBloc(gh<_i219.IOrderRepository>()),
);
return this; return this;
} }
} }

View File

@ -11,7 +11,7 @@ class MainPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AutoTabsRouter.pageView( return AutoTabsRouter.pageView(
routes: [HomeRoute(), TransactionRoute(), ReportRoute(), ProfileRoute()], routes: [HomeRoute(), OrderRoute(), ReportRoute(), ProfileRoute()],
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
builder: (context, child, pageController) { builder: (context, child, pageController) {
final tabsRouter = AutoTabsRouter.of(context); final tabsRouter = AutoTabsRouter.of(context);

View File

@ -33,8 +33,8 @@ class _MainBottomNavbarState extends State<MainBottomNavbar> {
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: LineIcon(LineIcons.moneyBill), icon: LineIcon(LineIcons.moneyBill),
label: context.lang.transaction, label: 'Order',
tooltip: context.lang.transaction, tooltip: 'Order',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: LineIcon(LineIcons.barChart), icon: LineIcon(LineIcons.barChart),

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,274 @@
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/order/order_loader/order_loader_bloc.dart';
import '../../../../common/theme/theme.dart';
import '../../../../injection.dart';
import '../../../components/appbar/appbar.dart';
import '../../../components/button/button.dart';
import '../../../components/spacer/spacer.dart';
import '../../../components/widgets/empty_widget.dart';
import '../../../router/app_router.gr.dart';
import 'widgets/status_tile.dart';
import 'widgets/order_tile.dart';
@RoutePage()
class OrderPage extends StatefulWidget implements AutoRouteWrapper {
const OrderPage({super.key});
@override
State<OrderPage> createState() => _OrderPageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (_) =>
getIt<OrderLoaderBloc>()
..add(OrderLoaderEvent.fetched(isRefresh: true)),
child: this,
);
}
class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
final ScrollController _scrollController = ScrollController();
// Filter state
String selectedFilter = 'All';
final List<String> filterOptions = ['All', 'Completed', 'Pending'];
@override
void initState() {
super.initState();
_fadeController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_slideController = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
CurvedAnimation(parent: _slideController, curve: Curves.elasticOut),
);
_fadeController.forward();
_slideController.forward();
}
@override
void dispose() {
_fadeController.dispose();
_slideController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: BlocListener<OrderLoaderBloc, OrderLoaderState>(
listenWhen: (p, c) => p.status != c.status,
listener: (context, state) {
context.read<OrderLoaderBloc>().add(
OrderLoaderEvent.fetched(isRefresh: true),
);
},
child: BlocBuilder<OrderLoaderBloc, OrderLoaderState>(
builder: (context, state) {
return NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollEndNotification &&
_scrollController.position.extentAfter == 0) {
context.read<OrderLoaderBloc>().add(
OrderLoaderEvent.fetched(),
);
return true;
}
return true;
},
child: CustomScrollView(
controller: _scrollController,
slivers: [
// Custom App Bar with Hero Effect
SliverAppBar(
expandedHeight: 120,
floating: true,
pinned: true,
backgroundColor: AppColor.primary,
centerTitle: false,
flexibleSpace: CustomAppBar(title: 'Order', isBack: false),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
SpaceWidth(8),
],
),
// Pinned Filter Section
SliverPersistentHeader(
pinned: true,
delegate: _FilterHeaderDelegate(
child: Container(
color: AppColor.background,
padding: EdgeInsets.fromLTRB(
AppValue.padding,
10,
AppValue.padding,
10,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: filterOptions.map((option) {
final index = filterOptions.indexOf(option);
return Padding(
padding: EdgeInsets.only(
right: index < filterOptions.length - 1
? 8
: 0,
),
child: OrderStatusTile(
label: option,
isSelected: option == selectedFilter,
onSelected: (isSelected) {
if (isSelected) {
setState(() {
selectedFilter = option;
});
if (option.toLowerCase() == 'all') {
context.read<OrderLoaderBloc>().add(
OrderLoaderEvent.statusChanged(
'',
),
);
} else {
context.read<OrderLoaderBloc>().add(
OrderLoaderEvent.statusChanged(
option.toLowerCase(),
),
);
}
}
},
),
);
}).toList(),
),
),
],
),
),
),
),
// Content
SliverPadding(
padding: EdgeInsets.all(AppValue.padding),
sliver: SliverList(
delegate: SliverChildListDelegate([
FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Column(
children: [
// Show filtered transaction count
if (selectedFilter != 'All')
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
children: [
Text(
'${state.orders.length} ${selectedFilter.toLowerCase()} order${state.orders.length != 1 ? 's' : ''}',
style: TextStyle(
color: AppColor.textSecondary,
fontSize: 14,
),
),
],
),
),
// Transaction List
state.orders.isEmpty
? EmptyWidget(
title: 'Order',
message:
'No ${selectedFilter.toLowerCase()} orders found',
)
: ListView.builder(
itemCount: state.orders.length,
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
return OrderTile(
onTap: () => context.router.push(
OrderDetailRoute(
order: state.orders[index],
),
),
order: state.orders[index],
);
},
),
],
),
),
),
]),
),
),
],
),
);
},
),
),
);
}
}
// Custom delegate for pinned filter header
class _FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
final Widget child;
_FilterHeaderDelegate({required this.child});
@override
double get minExtent => 70; // Minimum height when collapsed
@override
double get maxExtent => 70; // Maximum height when expanded
@override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
return child;
}
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}

View File

@ -1,42 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../../domain/order/order.dart';
// Model untuk Transaction class OrderTile extends StatelessWidget {
class Transaction { final Order order;
final String id;
final String customerName;
final DateTime date;
final double totalAmount;
final int itemCount;
final String paymentMethod;
final TransactionStatus status;
final String? receiptNumber;
Transaction({
required this.id,
required this.customerName,
required this.date,
required this.totalAmount,
required this.itemCount,
required this.paymentMethod,
required this.status,
this.receiptNumber,
});
}
enum TransactionStatus { completed, pending, cancelled, refunded }
class TransactionTile extends StatelessWidget {
final Transaction transaction;
final VoidCallback? onTap; final VoidCallback? onTap;
final VoidCallback? onPrint; final VoidCallback? onPrint;
final VoidCallback? onRefund; final VoidCallback? onRefund;
const TransactionTile({ const OrderTile({
super.key, super.key,
required this.transaction, required this.order,
this.onTap, this.onTap,
this.onPrint, this.onPrint,
this.onRefund, this.onRefund,
@ -73,8 +49,8 @@ class TransactionTile extends StatelessWidget {
_buildHeaderRow(), _buildHeaderRow(),
const SizedBox(height: 12), const SizedBox(height: 12),
// Transaction Info // Order Info
_buildTransactionInfo(), _buildOrderInfo(),
const SizedBox(height: 16), const SizedBox(height: 16),
// Amount Section // Amount Section
@ -99,7 +75,9 @@ class TransactionTile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
transaction.receiptNumber ?? 'TXN-${transaction.id}', order.orderNumber.isNotEmpty
? order.orderNumber
: 'ORD-${order.id}',
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -108,7 +86,7 @@ class TransactionTile extends StatelessWidget {
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
Text( Text(
DateFormat('dd MMM yyyy, HH:mm').format(transaction.date), _formatDate(order.createdAt),
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
color: AppColor.textSecondary, color: AppColor.textSecondary,
@ -126,27 +104,38 @@ class TransactionTile extends StatelessWidget {
String statusText; String statusText;
IconData statusIcon; IconData statusIcon;
switch (transaction.status) { // Check isVoid and isRefund first for display
case TransactionStatus.completed: if (order.isVoid) {
statusColor = AppColor.success; statusColor = AppColor.error;
statusText = 'Completed'; statusText = 'Void';
statusIcon = Icons.check_circle; statusIcon = Icons.block;
break; } else if (order.isRefund) {
case TransactionStatus.pending: statusColor = AppColor.info;
statusColor = AppColor.warning; statusText = 'Refunded';
statusText = 'Pending'; statusIcon = Icons.undo;
statusIcon = Icons.schedule; } else {
break; // Handle status values (only pending and completed)
case TransactionStatus.cancelled: switch (order.status.toLowerCase()) {
statusColor = AppColor.error; case 'completed':
statusText = 'Cancelled'; case 'paid':
statusIcon = Icons.cancel; case 'finished':
break; statusColor = AppColor.success;
case TransactionStatus.refunded: statusText = 'Completed';
statusColor = AppColor.info; statusIcon = Icons.check_circle;
statusText = 'Refunded'; break;
statusIcon = Icons.undo; case 'pending':
break; case 'waiting':
case 'processing':
statusColor = AppColor.warning;
statusText = 'Pending';
statusIcon = Icons.schedule;
break;
default:
statusColor = AppColor.textSecondary;
statusText = order.status;
statusIcon = Icons.info;
break;
}
} }
return Container( return Container(
@ -174,7 +163,7 @@ class TransactionTile extends StatelessWidget {
); );
} }
Widget _buildTransactionInfo() { Widget _buildOrderInfo() {
return Row( return Row(
children: [ children: [
Expanded( Expanded(
@ -184,11 +173,11 @@ class TransactionTile extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
Icon(Icons.person_outline, size: 16, color: AppColor.primary), Icon(_getOrderInfoIcon(), size: 16, color: AppColor.primary),
const SizedBox(width: 6), const SizedBox(width: 6),
Expanded( Expanded(
child: Text( child: Text(
transaction.customerName, _getOrderInfoText(),
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -209,7 +198,7 @@ class TransactionTile extends StatelessWidget {
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
'${transaction.itemCount} items', '${order.orderItems.length} items',
style: const TextStyle( style: const TextStyle(
fontSize: 13, fontSize: 13,
color: AppColor.textSecondary, color: AppColor.textSecondary,
@ -230,13 +219,13 @@ class TransactionTile extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( Icon(
_getPaymentIcon(transaction.paymentMethod), _getOrderTypeIcon(order.orderType),
size: 16, size: 16,
color: AppColor.primary, color: AppColor.primary,
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
transaction.paymentMethod, order.orderType.isNotEmpty ? order.orderType : 'Dine In',
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -285,13 +274,24 @@ class TransactionTile extends StatelessWidget {
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
'Rp ${NumberFormat('#,###').format(transaction.totalAmount)}', 'Rp ${NumberFormat('#,###').format(order.totalAmount)}',
style: const TextStyle( style: const TextStyle(
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: AppColor.textWhite, color: AppColor.textWhite,
), ),
), ),
if (order.remainingAmount > 0) ...[
const SizedBox(height: 4),
Text(
'Remaining: Rp ${NumberFormat('#,###').format(order.remainingAmount)}',
style: const TextStyle(
fontSize: 12,
color: AppColor.textWhite,
fontWeight: FontWeight.w400,
),
),
],
], ],
), ),
Container( Container(
@ -300,8 +300,8 @@ class TransactionTile extends StatelessWidget {
color: AppColor.backgroundLight.withOpacity(0.2), color: AppColor.backgroundLight.withOpacity(0.2),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: const Icon( child: Icon(
Icons.attach_money, _getPaymentStatusIcon(order.paymentStatus),
color: AppColor.textWhite, color: AppColor.textWhite,
size: 24, size: 24,
), ),
@ -312,19 +312,32 @@ class TransactionTile extends StatelessWidget {
} }
Widget _buildFooterActions() { Widget _buildFooterActions() {
// Don't show anything if order is void or refunded
if (order.isVoid || order.isRefund) {
return const SizedBox.shrink();
}
return Row( return Row(
children: [ children: [
Expanded( Expanded(
child: Text( child: Column(
'ID: ${transaction.id}', crossAxisAlignment: CrossAxisAlignment.start,
style: const TextStyle( children: [
fontSize: 11, if (order.payments.isNotEmpty) ...[
color: AppColor.textLight, const SizedBox(height: 2),
fontWeight: FontWeight.w500, Text(
), 'Payment: ${_getPaymentMethods()}',
style: const TextStyle(
fontSize: 11,
color: AppColor.textLight,
fontWeight: FontWeight.w400,
),
),
],
],
), ),
), ),
if (transaction.status == TransactionStatus.completed) ...[ if (order.status.toLowerCase() == 'completed') ...[
_buildActionButton( _buildActionButton(
icon: Icons.print, icon: Icons.print,
label: 'Print', label: 'Print',
@ -377,25 +390,90 @@ class TransactionTile extends StatelessWidget {
); );
} }
IconData _getPaymentIcon(String paymentMethod) { IconData _getOrderInfoIcon() {
switch (paymentMethod.toLowerCase()) { switch (order.orderType.toLowerCase()) {
case 'cash': case 'dine in':
return Icons.payments; case 'dine_in':
case 'card': return Icons.table_restaurant_outlined;
case 'credit card': case 'takeaway':
case 'debit card': case 'take_away':
return Icons.credit_card; case 'pickup':
case 'qris': return Icons.person_outline;
case 'qr code': case 'delivery':
return Icons.qr_code; return Icons.location_on_outlined;
case 'transfer':
case 'bank transfer':
return Icons.account_balance;
case 'e-wallet':
case 'digital wallet':
return Icons.account_balance_wallet;
default: default:
return Icons.payment; return Icons.receipt_outlined;
}
}
String _getOrderInfoText() {
switch (order.orderType.toLowerCase()) {
case 'dine in':
case 'dine_in':
return 'Table ${order.tableNumber.isNotEmpty ? order.tableNumber : 'N/A'}';
case 'takeaway':
case 'take_away':
case 'pickup':
return 'Pickup Order';
case 'delivery':
return 'Delivery Order';
default:
return order.tableNumber.isNotEmpty
? 'Table ${order.tableNumber}'
: 'Order ${order.orderNumber}';
}
}
IconData _getOrderTypeIcon(String orderType) {
switch (orderType.toLowerCase()) {
case 'dine in':
case 'dine_in':
return Icons.restaurant;
case 'takeaway':
case 'take_away':
case 'pickup':
return Icons.shopping_bag;
case 'delivery':
return Icons.delivery_dining;
default:
return Icons.restaurant_menu;
}
}
IconData _getPaymentStatusIcon(String paymentStatus) {
switch (paymentStatus.toLowerCase()) {
case 'paid':
case 'completed':
return Icons.check_circle;
case 'pending':
case 'partial':
return Icons.schedule;
case 'failed':
case 'cancelled':
return Icons.error;
default:
return Icons.attach_money;
}
}
String _getPaymentMethods() {
if (order.payments.isEmpty) return 'N/A';
// Get unique payment methods from payments
final methods = order.payments
.map((payment) => payment.paymentMethodName)
.toSet()
.join(', ');
return methods.isEmpty ? 'N/A' : methods;
}
String _formatDate(String dateString) {
try {
final date = DateTime.parse(dateString);
return DateFormat('dd MMM yyyy, HH:mm').format(date);
} catch (e) {
return dateString;
} }
} }
} }

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
class TransactionStatusTile extends StatelessWidget { class OrderStatusTile extends StatelessWidget {
final String label; final String label;
final bool isSelected; final bool isSelected;
final void Function(bool)? onSelected; final void Function(bool)? onSelected;
const TransactionStatusTile({ const OrderStatusTile({
super.key, super.key,
required this.label, required this.label,
this.isSelected = false, this.isSelected = false,

View File

@ -4,15 +4,15 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import 'package:shimmer/shimmer.dart'; import 'package:shimmer/shimmer.dart';
import '../../../application/category/category_loader/category_loader_bloc.dart'; import '../../../../application/category/category_loader/category_loader_bloc.dart';
import '../../../application/product/product_loader/product_loader_bloc.dart'; import '../../../../application/product/product_loader/product_loader_bloc.dart';
import '../../../common/theme/theme.dart'; import '../../../../common/theme/theme.dart';
import '../../../domain/category/category.dart'; import '../../../../domain/category/category.dart';
import '../../../domain/product/product.dart'; import '../../../../domain/product/product.dart';
import '../../../injection.dart'; import '../../../../injection.dart';
import '../../components/appbar/appbar.dart'; import '../../../components/appbar/appbar.dart';
import '../../components/button/button.dart'; import '../../../components/button/button.dart';
import '../../components/widgets/empty_widget.dart'; import '../../../components/widgets/empty_widget.dart';
import 'widgets/category_delegate.dart'; import 'widgets/category_delegate.dart';
import 'widgets/product_card.dart'; import 'widgets/product_card.dart';
import 'widgets/product_tile.dart'; import 'widgets/product_tile.dart';

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../domain/category/category.dart'; import '../../../../../domain/category/category.dart';
class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate { class ProductCategoryHeaderDelegate extends SliverPersistentHeaderDelegate {
final List<Category> categories; final List<Category> categories;

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart'; import '../../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../domain/product/product.dart'; import '../../../../../domain/product/product.dart';
import '../../../components/image/image.dart'; import '../../../../components/image/image.dart';
class ProductCard extends StatelessWidget { class ProductCard extends StatelessWidget {
const ProductCard({super.key, required this.product, this.onTap}); const ProductCard({super.key, required this.product, this.onTap});

View File

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart'; import '../../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../domain/product/product.dart'; import '../../../../../domain/product/product.dart';
import '../../../components/image/image.dart'; import '../../../../components/image/image.dart';
import '../../../components/spacer/spacer.dart'; import '../../../../components/spacer/spacer.dart';
class ProductTile extends StatelessWidget { class ProductTile extends StatelessWidget {
final Product product; final Product product;

View File

@ -1,296 +0,0 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/status_tile.dart';
import 'widgets/transaction_tile.dart';
@RoutePage()
class TransactionPage extends StatefulWidget {
const TransactionPage({super.key});
@override
State<TransactionPage> createState() => _TransactionPageState();
}
class _TransactionPageState extends State<TransactionPage>
with TickerProviderStateMixin {
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
// Filter state
String selectedFilter = 'All';
final List<String> filterOptions = [
'All',
'Completed',
'Pending',
'Refunded',
];
@override
void initState() {
super.initState();
_fadeController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_slideController = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
CurvedAnimation(parent: _slideController, curve: Curves.elasticOut),
);
_fadeController.forward();
_slideController.forward();
}
@override
void dispose() {
_fadeController.dispose();
_slideController.dispose();
super.dispose();
}
final sampleTransactions = [
Transaction(
id: 'TXN001',
customerName: 'John Doe',
date: DateTime.now().subtract(const Duration(hours: 2)),
totalAmount: 125000,
itemCount: 3,
paymentMethod: 'Cash',
status: TransactionStatus.completed,
receiptNumber: 'RCP-2024-001',
),
Transaction(
id: 'TXN002',
customerName: 'Jane Smith',
date: DateTime.now().subtract(const Duration(hours: 5)),
totalAmount: 87500,
itemCount: 2,
paymentMethod: 'QRIS',
status: TransactionStatus.pending,
receiptNumber: 'RCP-2024-002',
),
Transaction(
id: 'TXN003',
customerName: 'Bob Johnson',
date: DateTime.now().subtract(const Duration(days: 1)),
totalAmount: 250000,
itemCount: 5,
paymentMethod: 'Credit Card',
status: TransactionStatus.refunded,
receiptNumber: 'RCP-2024-003',
),
];
// Filter transactions based on selected status
List<Transaction> get filteredTransactions {
if (selectedFilter == 'All') {
return sampleTransactions;
}
TransactionStatus? filterStatus;
switch (selectedFilter) {
case 'Completed':
filterStatus = TransactionStatus.completed;
break;
case 'Pending':
filterStatus = TransactionStatus.pending;
break;
case 'Refunded':
filterStatus = TransactionStatus.refunded;
break;
}
return sampleTransactions
.where((transaction) => transaction.status == filterStatus)
.toList();
}
// Build filter chip
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(
slivers: [
// Custom App Bar with Hero Effect
SliverAppBar(
expandedHeight: 120,
floating: true,
pinned: true,
backgroundColor: AppColor.primary,
centerTitle: false,
flexibleSpace: CustomAppBar(title: 'Transaction', isBack: false),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
SpaceWidth(8),
],
),
// Pinned Filter Section
SliverPersistentHeader(
pinned: true,
delegate: _FilterHeaderDelegate(
child: Container(
color: AppColor.background,
padding: EdgeInsets.fromLTRB(
AppValue.padding,
10,
AppValue.padding,
10,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: filterOptions.map((option) {
final index = filterOptions.indexOf(option);
return Padding(
padding: EdgeInsets.only(
right: index < filterOptions.length - 1 ? 8 : 0,
),
child: TransactionStatusTile(
label: option,
isSelected: option == selectedFilter,
onSelected: (isSelected) {
if (isSelected) {
setState(() {
selectedFilter = option;
});
}
},
),
);
}).toList(),
),
),
],
),
),
),
),
// Content
SliverPadding(
padding: EdgeInsets.all(AppValue.padding),
sliver: SliverList(
delegate: SliverChildListDelegate([
FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Column(
children: [
// Show filtered transaction count
if (selectedFilter != 'All')
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
children: [
Text(
'${filteredTransactions.length} ${selectedFilter.toLowerCase()} transaction${filteredTransactions.length != 1 ? 's' : ''}',
style: TextStyle(
color: AppColor.textSecondary,
fontSize: 14,
),
),
],
),
),
// Transaction List
filteredTransactions.isEmpty
? Container(
padding: const EdgeInsets.symmetric(
vertical: 40,
),
child: Column(
children: [
Icon(
LineIcons.receipt,
size: 64,
color: AppColor.textSecondary.withOpacity(
0.5,
),
),
const SizedBox(height: 16),
Text(
'No ${selectedFilter.toLowerCase()} transactions found',
style: TextStyle(
color: AppColor.textSecondary,
fontSize: 16,
),
),
],
),
)
: Column(
children: filteredTransactions.map((
transaction,
) {
return TransactionTile(
transaction: transaction,
onTap: () {},
);
}).toList(),
),
],
),
),
),
]),
),
),
],
),
);
}
}
// Custom delegate for pinned filter header
class _FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
final Widget child;
_FilterHeaderDelegate({required this.child});
@override
double get minExtent => 70; // Minimum height when collapsed
@override
double get maxExtent => 70; // Maximum height when expanded
@override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
return child;
}
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}

View File

@ -1,97 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class TransactionAppBar extends StatelessWidget {
final Animation<double> rotationAnimation;
const TransactionAppBar({super.key, required this.rotationAnimation});
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 20, bottom: 16),
title: Text(
'Transaksi',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: rotationAnimation.value,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.1),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.5,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.05),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.2,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -16,7 +16,7 @@ class AppRouter extends RootStackRouter {
page: MainRoute.page, page: MainRoute.page,
children: [ children: [
AutoRoute(page: HomeRoute.page), AutoRoute(page: HomeRoute.page),
AutoRoute(page: TransactionRoute.page), AutoRoute(page: OrderRoute.page),
AutoRoute(page: ReportRoute.page), AutoRoute(page: ReportRoute.page),
AutoRoute(page: ProfileRoute.page), AutoRoute(page: ProfileRoute.page),
], ],
@ -51,5 +51,8 @@ class AppRouter extends RootStackRouter {
// Error // Error
AutoRoute(page: ErrorRoute.page), AutoRoute(page: ErrorRoute.page),
// Order
AutoRoute(page: OrderDetailRoute.page),
]; ];
} }

View File

@ -9,6 +9,7 @@
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes // ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:apskel_owner_flutter/domain/order/order.dart' as _i21;
import 'package:apskel_owner_flutter/presentation/pages/auth/login/login_page.dart' import 'package:apskel_owner_flutter/presentation/pages/auth/login/login_page.dart'
as _i8; as _i8;
import 'package:apskel_owner_flutter/presentation/pages/customer/customer_page.dart' import 'package:apskel_owner_flutter/presentation/pages/customer/customer_page.dart'
@ -27,50 +28,52 @@ import 'package:apskel_owner_flutter/presentation/pages/language/language_page.d
as _i7; as _i7;
import 'package:apskel_owner_flutter/presentation/pages/main/main_page.dart' import 'package:apskel_owner_flutter/presentation/pages/main/main_page.dart'
as _i9; as _i9;
import 'package:apskel_owner_flutter/presentation/pages/product/product_page.dart' import 'package:apskel_owner_flutter/presentation/pages/order/order_detail/order_detail_page.dart'
as _i10; as _i10;
import 'package:apskel_owner_flutter/presentation/pages/profile/profile_page.dart' import 'package:apskel_owner_flutter/presentation/pages/order/order_list/order_page.dart'
as _i11; as _i11;
import 'package:apskel_owner_flutter/presentation/pages/purchase/purchase_page.dart' import 'package:apskel_owner_flutter/presentation/pages/product/product_list/product_page.dart'
as _i12; as _i12;
import 'package:apskel_owner_flutter/presentation/pages/report/report_page.dart' import 'package:apskel_owner_flutter/presentation/pages/profile/profile_page.dart'
as _i13; as _i13;
import 'package:apskel_owner_flutter/presentation/pages/sales/sales_page.dart' import 'package:apskel_owner_flutter/presentation/pages/purchase/purchase_page.dart'
as _i14; as _i14;
import 'package:apskel_owner_flutter/presentation/pages/schedule/schedule_page.dart' import 'package:apskel_owner_flutter/presentation/pages/report/report_page.dart'
as _i15; as _i15;
import 'package:apskel_owner_flutter/presentation/pages/splash/splash_page.dart' import 'package:apskel_owner_flutter/presentation/pages/sales/sales_page.dart'
as _i16; as _i16;
import 'package:apskel_owner_flutter/presentation/pages/transaction/transaction_page.dart' import 'package:apskel_owner_flutter/presentation/pages/schedule/schedule_page.dart'
as _i17; as _i17;
import 'package:auto_route/auto_route.dart' as _i18; import 'package:apskel_owner_flutter/presentation/pages/splash/splash_page.dart'
import 'package:flutter/material.dart' as _i19; as _i18;
import 'package:auto_route/auto_route.dart' as _i19;
import 'package:flutter/material.dart' as _i20;
/// generated route for /// generated route for
/// [_i1.CustomerPage] /// [_i1.CustomerPage]
class CustomerRoute extends _i18.PageRouteInfo<void> { class CustomerRoute extends _i19.PageRouteInfo<void> {
const CustomerRoute({List<_i18.PageRouteInfo>? children}) const CustomerRoute({List<_i19.PageRouteInfo>? children})
: super(CustomerRoute.name, initialChildren: children); : super(CustomerRoute.name, initialChildren: children);
static const String name = 'CustomerRoute'; static const String name = 'CustomerRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i1.CustomerPage()); return _i19.WrappedRoute(child: const _i1.CustomerPage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i2.DailyTasksFormPage] /// [_i2.DailyTasksFormPage]
class DailyTasksFormRoute extends _i18.PageRouteInfo<void> { class DailyTasksFormRoute extends _i19.PageRouteInfo<void> {
const DailyTasksFormRoute({List<_i18.PageRouteInfo>? children}) const DailyTasksFormRoute({List<_i19.PageRouteInfo>? children})
: super(DailyTasksFormRoute.name, initialChildren: children); : super(DailyTasksFormRoute.name, initialChildren: children);
static const String name = 'DailyTasksFormRoute'; static const String name = 'DailyTasksFormRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i2.DailyTasksFormPage(); return const _i2.DailyTasksFormPage();
@ -80,16 +83,16 @@ class DailyTasksFormRoute extends _i18.PageRouteInfo<void> {
/// generated route for /// generated route for
/// [_i3.ErrorPage] /// [_i3.ErrorPage]
class ErrorRoute extends _i18.PageRouteInfo<ErrorRouteArgs> { class ErrorRoute extends _i19.PageRouteInfo<ErrorRouteArgs> {
ErrorRoute({ ErrorRoute({
_i19.Key? key, _i20.Key? key,
String? title, String? title,
String? message, String? message,
_i19.VoidCallback? onRetry, _i20.VoidCallback? onRetry,
_i19.VoidCallback? onBack, _i20.VoidCallback? onBack,
String? errorCode, String? errorCode,
_i19.IconData? errorIcon, _i20.IconData? errorIcon,
List<_i18.PageRouteInfo>? children, List<_i19.PageRouteInfo>? children,
}) : super( }) : super(
ErrorRoute.name, ErrorRoute.name,
args: ErrorRouteArgs( args: ErrorRouteArgs(
@ -106,7 +109,7 @@ class ErrorRoute extends _i18.PageRouteInfo<ErrorRouteArgs> {
static const String name = 'ErrorRoute'; static const String name = 'ErrorRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
final args = data.argsAs<ErrorRouteArgs>( final args = data.argsAs<ErrorRouteArgs>(
@ -136,19 +139,19 @@ class ErrorRouteArgs {
this.errorIcon, this.errorIcon,
}); });
final _i19.Key? key; final _i20.Key? key;
final String? title; final String? title;
final String? message; final String? message;
final _i19.VoidCallback? onRetry; final _i20.VoidCallback? onRetry;
final _i19.VoidCallback? onBack; final _i20.VoidCallback? onBack;
final String? errorCode; final String? errorCode;
final _i19.IconData? errorIcon; final _i20.IconData? errorIcon;
@override @override
String toString() { String toString() {
@ -158,29 +161,29 @@ class ErrorRouteArgs {
/// generated route for /// generated route for
/// [_i4.FinancePage] /// [_i4.FinancePage]
class FinanceRoute extends _i18.PageRouteInfo<void> { class FinanceRoute extends _i19.PageRouteInfo<void> {
const FinanceRoute({List<_i18.PageRouteInfo>? children}) const FinanceRoute({List<_i19.PageRouteInfo>? children})
: super(FinanceRoute.name, initialChildren: children); : super(FinanceRoute.name, initialChildren: children);
static const String name = 'FinanceRoute'; static const String name = 'FinanceRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i4.FinancePage()); return _i19.WrappedRoute(child: const _i4.FinancePage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i5.HomePage] /// [_i5.HomePage]
class HomeRoute extends _i18.PageRouteInfo<void> { class HomeRoute extends _i19.PageRouteInfo<void> {
const HomeRoute({List<_i18.PageRouteInfo>? children}) const HomeRoute({List<_i19.PageRouteInfo>? children})
: super(HomeRoute.name, initialChildren: children); : super(HomeRoute.name, initialChildren: children);
static const String name = 'HomeRoute'; static const String name = 'HomeRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i5.HomePage(); return const _i5.HomePage();
@ -190,29 +193,29 @@ class HomeRoute extends _i18.PageRouteInfo<void> {
/// generated route for /// generated route for
/// [_i6.InventoryPage] /// [_i6.InventoryPage]
class InventoryRoute extends _i18.PageRouteInfo<void> { class InventoryRoute extends _i19.PageRouteInfo<void> {
const InventoryRoute({List<_i18.PageRouteInfo>? children}) const InventoryRoute({List<_i19.PageRouteInfo>? children})
: super(InventoryRoute.name, initialChildren: children); : super(InventoryRoute.name, initialChildren: children);
static const String name = 'InventoryRoute'; static const String name = 'InventoryRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i6.InventoryPage()); return _i19.WrappedRoute(child: const _i6.InventoryPage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i7.LanguagePage] /// [_i7.LanguagePage]
class LanguageRoute extends _i18.PageRouteInfo<void> { class LanguageRoute extends _i19.PageRouteInfo<void> {
const LanguageRoute({List<_i18.PageRouteInfo>? children}) const LanguageRoute({List<_i19.PageRouteInfo>? children})
: super(LanguageRoute.name, initialChildren: children); : super(LanguageRoute.name, initialChildren: children);
static const String name = 'LanguageRoute'; static const String name = 'LanguageRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i7.LanguagePage(); return const _i7.LanguagePage();
@ -222,29 +225,29 @@ class LanguageRoute extends _i18.PageRouteInfo<void> {
/// generated route for /// generated route for
/// [_i8.LoginPage] /// [_i8.LoginPage]
class LoginRoute extends _i18.PageRouteInfo<void> { class LoginRoute extends _i19.PageRouteInfo<void> {
const LoginRoute({List<_i18.PageRouteInfo>? children}) const LoginRoute({List<_i19.PageRouteInfo>? children})
: super(LoginRoute.name, initialChildren: children); : super(LoginRoute.name, initialChildren: children);
static const String name = 'LoginRoute'; static const String name = 'LoginRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i8.LoginPage()); return _i19.WrappedRoute(child: const _i8.LoginPage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i9.MainPage] /// [_i9.MainPage]
class MainRoute extends _i18.PageRouteInfo<void> { class MainRoute extends _i19.PageRouteInfo<void> {
const MainRoute({List<_i18.PageRouteInfo>? children}) const MainRoute({List<_i19.PageRouteInfo>? children})
: super(MainRoute.name, initialChildren: children); : super(MainRoute.name, initialChildren: children);
static const String name = 'MainRoute'; static const String name = 'MainRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i9.MainPage(); return const _i9.MainPage();
@ -253,129 +256,166 @@ class MainRoute extends _i18.PageRouteInfo<void> {
} }
/// generated route for /// generated route for
/// [_i10.ProductPage] /// [_i10.OrderDetailPage]
class ProductRoute extends _i18.PageRouteInfo<void> { class OrderDetailRoute extends _i19.PageRouteInfo<OrderDetailRouteArgs> {
const ProductRoute({List<_i18.PageRouteInfo>? children}) OrderDetailRoute({
_i20.Key? key,
required _i21.Order order,
List<_i19.PageRouteInfo>? children,
}) : super(
OrderDetailRoute.name,
args: OrderDetailRouteArgs(key: key, order: order),
initialChildren: children,
);
static const String name = 'OrderDetailRoute';
static _i19.PageInfo page = _i19.PageInfo(
name,
builder: (data) {
final args = data.argsAs<OrderDetailRouteArgs>();
return _i10.OrderDetailPage(key: args.key, order: args.order);
},
);
}
class OrderDetailRouteArgs {
const OrderDetailRouteArgs({this.key, required this.order});
final _i20.Key? key;
final _i21.Order order;
@override
String toString() {
return 'OrderDetailRouteArgs{key: $key, order: $order}';
}
}
/// generated route for
/// [_i11.OrderPage]
class OrderRoute extends _i19.PageRouteInfo<void> {
const OrderRoute({List<_i19.PageRouteInfo>? children})
: super(OrderRoute.name, initialChildren: children);
static const String name = 'OrderRoute';
static _i19.PageInfo page = _i19.PageInfo(
name,
builder: (data) {
return _i19.WrappedRoute(child: const _i11.OrderPage());
},
);
}
/// generated route for
/// [_i12.ProductPage]
class ProductRoute extends _i19.PageRouteInfo<void> {
const ProductRoute({List<_i19.PageRouteInfo>? children})
: super(ProductRoute.name, initialChildren: children); : super(ProductRoute.name, initialChildren: children);
static const String name = 'ProductRoute'; static const String name = 'ProductRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i10.ProductPage()); return _i19.WrappedRoute(child: const _i12.ProductPage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i11.ProfilePage] /// [_i13.ProfilePage]
class ProfileRoute extends _i18.PageRouteInfo<void> { class ProfileRoute extends _i19.PageRouteInfo<void> {
const ProfileRoute({List<_i18.PageRouteInfo>? children}) const ProfileRoute({List<_i19.PageRouteInfo>? children})
: super(ProfileRoute.name, initialChildren: children); : super(ProfileRoute.name, initialChildren: children);
static const String name = 'ProfileRoute'; static const String name = 'ProfileRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i11.ProfilePage()); return _i19.WrappedRoute(child: const _i13.ProfilePage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i12.PurchasePage] /// [_i14.PurchasePage]
class PurchaseRoute extends _i18.PageRouteInfo<void> { class PurchaseRoute extends _i19.PageRouteInfo<void> {
const PurchaseRoute({List<_i18.PageRouteInfo>? children}) const PurchaseRoute({List<_i19.PageRouteInfo>? children})
: super(PurchaseRoute.name, initialChildren: children); : super(PurchaseRoute.name, initialChildren: children);
static const String name = 'PurchaseRoute'; static const String name = 'PurchaseRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i12.PurchasePage(); return const _i14.PurchasePage();
}, },
); );
} }
/// generated route for /// generated route for
/// [_i13.ReportPage] /// [_i15.ReportPage]
class ReportRoute extends _i18.PageRouteInfo<void> { class ReportRoute extends _i19.PageRouteInfo<void> {
const ReportRoute({List<_i18.PageRouteInfo>? children}) const ReportRoute({List<_i19.PageRouteInfo>? children})
: super(ReportRoute.name, initialChildren: children); : super(ReportRoute.name, initialChildren: children);
static const String name = 'ReportRoute'; static const String name = 'ReportRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i13.ReportPage()); return _i19.WrappedRoute(child: const _i15.ReportPage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i14.SalesPage] /// [_i16.SalesPage]
class SalesRoute extends _i18.PageRouteInfo<void> { class SalesRoute extends _i19.PageRouteInfo<void> {
const SalesRoute({List<_i18.PageRouteInfo>? children}) const SalesRoute({List<_i19.PageRouteInfo>? children})
: super(SalesRoute.name, initialChildren: children); : super(SalesRoute.name, initialChildren: children);
static const String name = 'SalesRoute'; static const String name = 'SalesRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return _i18.WrappedRoute(child: const _i14.SalesPage()); return _i19.WrappedRoute(child: const _i16.SalesPage());
}, },
); );
} }
/// generated route for /// generated route for
/// [_i15.SchedulePage] /// [_i17.SchedulePage]
class ScheduleRoute extends _i18.PageRouteInfo<void> { class ScheduleRoute extends _i19.PageRouteInfo<void> {
const ScheduleRoute({List<_i18.PageRouteInfo>? children}) const ScheduleRoute({List<_i19.PageRouteInfo>? children})
: super(ScheduleRoute.name, initialChildren: children); : super(ScheduleRoute.name, initialChildren: children);
static const String name = 'ScheduleRoute'; static const String name = 'ScheduleRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i15.SchedulePage(); return const _i17.SchedulePage();
}, },
); );
} }
/// generated route for /// generated route for
/// [_i16.SplashPage] /// [_i18.SplashPage]
class SplashRoute extends _i18.PageRouteInfo<void> { class SplashRoute extends _i19.PageRouteInfo<void> {
const SplashRoute({List<_i18.PageRouteInfo>? children}) const SplashRoute({List<_i19.PageRouteInfo>? children})
: super(SplashRoute.name, initialChildren: children); : super(SplashRoute.name, initialChildren: children);
static const String name = 'SplashRoute'; static const String name = 'SplashRoute';
static _i18.PageInfo page = _i18.PageInfo( static _i19.PageInfo page = _i19.PageInfo(
name, name,
builder: (data) { builder: (data) {
return const _i16.SplashPage(); return const _i18.SplashPage();
},
);
}
/// generated route for
/// [_i17.TransactionPage]
class TransactionRoute extends _i18.PageRouteInfo<void> {
const TransactionRoute({List<_i18.PageRouteInfo>? children})
: super(TransactionRoute.name, initialChildren: children);
static const String name = 'TransactionRoute';
static _i18.PageInfo page = _i18.PageInfo(
name,
builder: (data) {
return const _i17.TransactionPage();
}, },
); );
} }