feat: order
This commit is contained in:
parent
62eb15b27f
commit
d3f2cb300c
90
lib/application/order/order_loader/order_loader_bloc.dart
Normal file
90
lib/application/order/order_loader/order_loader_bloc.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
17
lib/application/order/order_loader/order_loader_state.dart
Normal file
17
lib/application/order/order_loader/order_loader_state.dart
Normal 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());
|
||||||
|
}
|
||||||
@ -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';
|
||||||
}
|
}
|
||||||
|
|||||||
161
lib/domain/order/entities/order_entity.dart
Normal file
161
lib/domain/order/entities/order_entity.dart
Normal 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: '',
|
||||||
|
);
|
||||||
|
}
|
||||||
10
lib/domain/order/failures/order_failure.dart
Normal file
10
lib/domain/order/failures/order_failure.dart
Normal 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;
|
||||||
|
}
|
||||||
10
lib/domain/order/order.dart
Normal file
10
lib/domain/order/order.dart
Normal 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';
|
||||||
2538
lib/domain/order/order.freezed.dart
Normal file
2538
lib/domain/order/order.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
10
lib/domain/order/repositories/i_order_repository.dart
Normal file
10
lib/domain/order/repositories/i_order_repository.dart
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
183
lib/infrastructure/order/dto/order_dto.dart
Normal file
183
lib/infrastructure/order/dto/order_dto.dart
Normal 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 ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
8
lib/infrastructure/order/order_dtos.dart
Normal file
8
lib/infrastructure/order/order_dtos.dart
Normal 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';
|
||||||
2197
lib/infrastructure/order/order_dtos.freezed.dart
Normal file
2197
lib/infrastructure/order/order_dtos.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
173
lib/infrastructure/order/order_dtos.g.dart
Normal file
173
lib/infrastructure/order/order_dtos.g.dart
Normal 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,
|
||||||
|
};
|
||||||
43
lib/infrastructure/order/repositories/order_repository.dart
Normal file
43
lib/infrastructure/order/repositories/order_repository.dart
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,32 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
|
import '../../../application/order/order_loader/order_loader_bloc.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.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/spacer/spacer.dart';
|
import '../../components/spacer/spacer.dart';
|
||||||
|
import '../../components/widgets/empty_widget.dart';
|
||||||
import 'widgets/status_tile.dart';
|
import 'widgets/status_tile.dart';
|
||||||
import 'widgets/order_tile.dart';
|
import 'widgets/order_tile.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class OrderPage extends StatefulWidget {
|
class OrderPage extends StatefulWidget implements AutoRouteWrapper {
|
||||||
const OrderPage({super.key});
|
const OrderPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<OrderPage> createState() => _OrderPageState();
|
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 {
|
class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
||||||
@ -22,15 +34,11 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
late AnimationController _slideController;
|
late AnimationController _slideController;
|
||||||
late Animation<double> _fadeAnimation;
|
late Animation<double> _fadeAnimation;
|
||||||
late Animation<Offset> _slideAnimation;
|
late Animation<Offset> _slideAnimation;
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
// Filter state
|
// Filter state
|
||||||
String selectedFilter = 'All';
|
String selectedFilter = 'All';
|
||||||
final List<String> filterOptions = [
|
final List<String> filterOptions = ['All', 'Completed', 'Pending'];
|
||||||
'All',
|
|
||||||
'Completed',
|
|
||||||
'Pending',
|
|
||||||
'Refunded',
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -66,202 +74,168 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
super.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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppColor.background,
|
backgroundColor: AppColor.background,
|
||||||
body: CustomScrollView(
|
body: BlocListener<OrderLoaderBloc, OrderLoaderState>(
|
||||||
slivers: [
|
listenWhen: (p, c) => p.status != c.status,
|
||||||
// Custom App Bar with Hero Effect
|
listener: (context, state) {
|
||||||
SliverAppBar(
|
context.read<OrderLoaderBloc>().add(
|
||||||
expandedHeight: 120,
|
OrderLoaderEvent.fetched(isRefresh: true),
|
||||||
floating: true,
|
);
|
||||||
pinned: true,
|
},
|
||||||
backgroundColor: AppColor.primary,
|
child: BlocBuilder<OrderLoaderBloc, OrderLoaderState>(
|
||||||
centerTitle: false,
|
builder: (context, state) {
|
||||||
flexibleSpace: CustomAppBar(title: 'Order', isBack: false),
|
return NotificationListener<ScrollNotification>(
|
||||||
actions: [
|
onNotification: (notification) {
|
||||||
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
|
if (notification is ScrollEndNotification &&
|
||||||
SpaceWidth(8),
|
_scrollController.position.extentAfter == 0) {
|
||||||
],
|
context.read<OrderLoaderBloc>().add(
|
||||||
),
|
OrderLoaderEvent.fetched(),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Pinned Filter Section
|
return true;
|
||||||
SliverPersistentHeader(
|
},
|
||||||
pinned: true,
|
child: CustomScrollView(
|
||||||
delegate: _FilterHeaderDelegate(
|
controller: _scrollController,
|
||||||
child: Container(
|
slivers: [
|
||||||
color: AppColor.background,
|
// Custom App Bar with Hero Effect
|
||||||
padding: EdgeInsets.fromLTRB(
|
SliverAppBar(
|
||||||
AppValue.padding,
|
expandedHeight: 120,
|
||||||
10,
|
floating: true,
|
||||||
AppValue.padding,
|
pinned: true,
|
||||||
10,
|
backgroundColor: AppColor.primary,
|
||||||
),
|
centerTitle: false,
|
||||||
child: Column(
|
flexibleSpace: CustomAppBar(title: 'Order', isBack: false),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
actions: [
|
||||||
children: [
|
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
|
||||||
SingleChildScrollView(
|
SpaceWidth(8),
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Content
|
// Pinned Filter Section
|
||||||
SliverPadding(
|
SliverPersistentHeader(
|
||||||
padding: EdgeInsets.all(AppValue.padding),
|
pinned: true,
|
||||||
sliver: SliverList(
|
delegate: _FilterHeaderDelegate(
|
||||||
delegate: SliverChildListDelegate([
|
child: Container(
|
||||||
FadeTransition(
|
color: AppColor.background,
|
||||||
opacity: _fadeAnimation,
|
padding: EdgeInsets.fromLTRB(
|
||||||
child: SlideTransition(
|
AppValue.padding,
|
||||||
position: _slideAnimation,
|
10,
|
||||||
child: Column(
|
AppValue.padding,
|
||||||
children: [
|
10,
|
||||||
// Show filtered transaction count
|
),
|
||||||
if (selectedFilter != 'All')
|
child: Column(
|
||||||
Padding(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
padding: const EdgeInsets.only(bottom: 16),
|
children: [
|
||||||
child: Row(
|
SingleChildScrollView(
|
||||||
children: [
|
scrollDirection: Axis.horizontal,
|
||||||
Text(
|
child: Row(
|
||||||
'${filteredTransactions.length} ${selectedFilter.toLowerCase()} transaction${filteredTransactions.length != 1 ? 's' : ''}',
|
children: filterOptions.map((option) {
|
||||||
style: TextStyle(
|
final index = filterOptions.indexOf(option);
|
||||||
color: AppColor.textSecondary,
|
return Padding(
|
||||||
fontSize: 14,
|
padding: EdgeInsets.only(
|
||||||
),
|
right: index < filterOptions.length - 1
|
||||||
),
|
? 8
|
||||||
],
|
: 0,
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// 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),
|
child: OrderStatusTile(
|
||||||
Text(
|
label: option,
|
||||||
'No ${selectedFilter.toLowerCase()} transactions found',
|
isSelected: option == selectedFilter,
|
||||||
style: TextStyle(
|
onSelected: (isSelected) {
|
||||||
color: AppColor.textSecondary,
|
if (isSelected) {
|
||||||
fontSize: 16,
|
setState(() {
|
||||||
),
|
selectedFilter = option;
|
||||||
|
});
|
||||||
|
if (option.toLowerCase() == 'all') {
|
||||||
|
context.read<OrderLoaderBloc>().add(
|
||||||
|
OrderLoaderEvent.statusChanged(
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
context.read<OrderLoaderBloc>().add(
|
||||||
|
OrderLoaderEvent.statusChanged(
|
||||||
|
option.toLowerCase(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Column(
|
|
||||||
children: filteredTransactions.map((
|
|
||||||
transaction,
|
|
||||||
) {
|
|
||||||
return OrderTile(
|
|
||||||
transaction: transaction,
|
|
||||||
onTap: () {},
|
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).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: () {},
|
||||||
|
order: state.orders[index],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,41 +2,17 @@ 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 Transaction {
|
|
||||||
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 OrderTile extends StatelessWidget {
|
class OrderTile extends StatelessWidget {
|
||||||
final Transaction transaction;
|
final Order order;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
final VoidCallback? onPrint;
|
final VoidCallback? onPrint;
|
||||||
final VoidCallback? onRefund;
|
final VoidCallback? onRefund;
|
||||||
|
|
||||||
const OrderTile({
|
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 OrderTile 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 OrderTile 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 OrderTile 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 OrderTile 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 OrderTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTransactionInfo() {
|
Widget _buildOrderInfo() {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -184,11 +173,11 @@ class OrderTile 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 OrderTile 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 OrderTile 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 OrderTile 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 OrderTile 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 OrderTile 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 OrderTile 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user