diff --git a/lib/application/customer/customer_loader/customer_loader_bloc.dart b/lib/application/customer/customer_loader/customer_loader_bloc.dart new file mode 100644 index 0000000..16cbb6d --- /dev/null +++ b/lib/application/customer/customer_loader/customer_loader_bloc.dart @@ -0,0 +1,82 @@ +import 'package:bloc/bloc.dart'; +import 'package:dartz/dartz.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:injectable/injectable.dart'; +import '../../../domain/customer/customer.dart'; + +part 'customer_loader_event.dart'; +part 'customer_loader_state.dart'; +part 'customer_loader_bloc.freezed.dart'; + +@injectable +class CustomerLoaderBloc + extends Bloc { + final ICustomerRepository _repository; + CustomerLoaderBloc(this._repository) : super(CustomerLoaderState.initial()) { + on(_onCustomerLoaderEvent); + } + + Future _onCustomerLoaderEvent( + CustomerLoaderEvent event, + Emitter emit, + ) { + return event.map( + fetched: (e) async { + var newState = state; + + if (e.isRefresh) { + newState = newState.copyWith(isFetching: true); + emit(newState); + } + + newState = await _mapFetchedToState(newState, isRefresh: e.isRefresh); + + emit(newState); + }, + setSelectedCustomer: (e) async { + emit(state.copyWith(selectedCustomer: e.customer)); + }, + ); + } + + Future _mapFetchedToState( + CustomerLoaderState state, { + bool isRefresh = false, + }) async { + state = state.copyWith(isFetching: false); + + if (state.hasReachedMax && state.customers.isNotEmpty && !isRefresh) { + return state; + } + + if (isRefresh) { + state = state.copyWith( + page: 1, + failureOrOption: none(), + hasReachedMax: false, + customers: [], + ); + } + + final failureOrCustomer = await _repository.getCustomer(page: state.page); + + state = failureOrCustomer.fold( + (f) { + if (state.customers.isNotEmpty) { + return state.copyWith(hasReachedMax: true); + } + return state.copyWith(failureOrOption: optionOf(f)); + }, + (customers) { + return state.copyWith( + customers: List.from(state.customers)..addAll(customers.customers), + failureOrOption: none(), + page: state.page + 1, + hasReachedMax: customers.customers.length < 10, + ); + }, + ); + + return state; + } +} diff --git a/lib/application/customer/customer_loader/customer_loader_bloc.freezed.dart b/lib/application/customer/customer_loader/customer_loader_bloc.freezed.dart new file mode 100644 index 0000000..e11dc00 --- /dev/null +++ b/lib/application/customer/customer_loader/customer_loader_bloc.freezed.dart @@ -0,0 +1,668 @@ +// 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 'customer_loader_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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 _$CustomerLoaderEvent { + @optionalTypeArgs + TResult when({ + required TResult Function(Customer customer) setSelectedCustomer, + required TResult Function(bool isRefresh) fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(Customer customer)? setSelectedCustomer, + TResult? Function(bool isRefresh)? fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(Customer customer)? setSelectedCustomer, + TResult Function(bool isRefresh)? fetched, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_SetSelectedCustomer value) setSelectedCustomer, + required TResult Function(_Fetched value) fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_SetSelectedCustomer value)? setSelectedCustomer, + TResult? Function(_Fetched value)? fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SetSelectedCustomer value)? setSelectedCustomer, + TResult Function(_Fetched value)? fetched, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CustomerLoaderEventCopyWith<$Res> { + factory $CustomerLoaderEventCopyWith( + CustomerLoaderEvent value, + $Res Function(CustomerLoaderEvent) then, + ) = _$CustomerLoaderEventCopyWithImpl<$Res, CustomerLoaderEvent>; +} + +/// @nodoc +class _$CustomerLoaderEventCopyWithImpl<$Res, $Val extends CustomerLoaderEvent> + implements $CustomerLoaderEventCopyWith<$Res> { + _$CustomerLoaderEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CustomerLoaderEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$SetSelectedCustomerImplCopyWith<$Res> { + factory _$$SetSelectedCustomerImplCopyWith( + _$SetSelectedCustomerImpl value, + $Res Function(_$SetSelectedCustomerImpl) then, + ) = __$$SetSelectedCustomerImplCopyWithImpl<$Res>; + @useResult + $Res call({Customer customer}); + + $CustomerCopyWith<$Res> get customer; +} + +/// @nodoc +class __$$SetSelectedCustomerImplCopyWithImpl<$Res> + extends _$CustomerLoaderEventCopyWithImpl<$Res, _$SetSelectedCustomerImpl> + implements _$$SetSelectedCustomerImplCopyWith<$Res> { + __$$SetSelectedCustomerImplCopyWithImpl( + _$SetSelectedCustomerImpl _value, + $Res Function(_$SetSelectedCustomerImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? customer = null}) { + return _then( + _$SetSelectedCustomerImpl( + null == customer + ? _value.customer + : customer // ignore: cast_nullable_to_non_nullable + as Customer, + ), + ); + } + + /// Create a copy of CustomerLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $CustomerCopyWith<$Res> get customer { + return $CustomerCopyWith<$Res>(_value.customer, (value) { + return _then(_value.copyWith(customer: value)); + }); + } +} + +/// @nodoc + +class _$SetSelectedCustomerImpl implements _SetSelectedCustomer { + const _$SetSelectedCustomerImpl(this.customer); + + @override + final Customer customer; + + @override + String toString() { + return 'CustomerLoaderEvent.setSelectedCustomer(customer: $customer)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SetSelectedCustomerImpl && + (identical(other.customer, customer) || + other.customer == customer)); + } + + @override + int get hashCode => Object.hash(runtimeType, customer); + + /// Create a copy of CustomerLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SetSelectedCustomerImplCopyWith<_$SetSelectedCustomerImpl> get copyWith => + __$$SetSelectedCustomerImplCopyWithImpl<_$SetSelectedCustomerImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(Customer customer) setSelectedCustomer, + required TResult Function(bool isRefresh) fetched, + }) { + return setSelectedCustomer(customer); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(Customer customer)? setSelectedCustomer, + TResult? Function(bool isRefresh)? fetched, + }) { + return setSelectedCustomer?.call(customer); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(Customer customer)? setSelectedCustomer, + TResult Function(bool isRefresh)? fetched, + required TResult orElse(), + }) { + if (setSelectedCustomer != null) { + return setSelectedCustomer(customer); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_SetSelectedCustomer value) setSelectedCustomer, + required TResult Function(_Fetched value) fetched, + }) { + return setSelectedCustomer(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_SetSelectedCustomer value)? setSelectedCustomer, + TResult? Function(_Fetched value)? fetched, + }) { + return setSelectedCustomer?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SetSelectedCustomer value)? setSelectedCustomer, + TResult Function(_Fetched value)? fetched, + required TResult orElse(), + }) { + if (setSelectedCustomer != null) { + return setSelectedCustomer(this); + } + return orElse(); + } +} + +abstract class _SetSelectedCustomer implements CustomerLoaderEvent { + const factory _SetSelectedCustomer(final Customer customer) = + _$SetSelectedCustomerImpl; + + Customer get customer; + + /// Create a copy of CustomerLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SetSelectedCustomerImplCopyWith<_$SetSelectedCustomerImpl> 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 _$CustomerLoaderEventCopyWithImpl<$Res, _$FetchedImpl> + implements _$$FetchedImplCopyWith<$Res> { + __$$FetchedImplCopyWithImpl( + _$FetchedImpl _value, + $Res Function(_$FetchedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerLoaderEvent + /// 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 'CustomerLoaderEvent.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 CustomerLoaderEvent + /// 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({ + required TResult Function(Customer customer) setSelectedCustomer, + required TResult Function(bool isRefresh) fetched, + }) { + return fetched(isRefresh); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(Customer customer)? setSelectedCustomer, + TResult? Function(bool isRefresh)? fetched, + }) { + return fetched?.call(isRefresh); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(Customer customer)? setSelectedCustomer, + TResult Function(bool isRefresh)? fetched, + required TResult orElse(), + }) { + if (fetched != null) { + return fetched(isRefresh); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_SetSelectedCustomer value) setSelectedCustomer, + required TResult Function(_Fetched value) fetched, + }) { + return fetched(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_SetSelectedCustomer value)? setSelectedCustomer, + TResult? Function(_Fetched value)? fetched, + }) { + return fetched?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SetSelectedCustomer value)? setSelectedCustomer, + TResult Function(_Fetched value)? fetched, + required TResult orElse(), + }) { + if (fetched != null) { + return fetched(this); + } + return orElse(); + } +} + +abstract class _Fetched implements CustomerLoaderEvent { + const factory _Fetched({final bool isRefresh}) = _$FetchedImpl; + + bool get isRefresh; + + /// Create a copy of CustomerLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$FetchedImplCopyWith<_$FetchedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$CustomerLoaderState { + List get customers => throw _privateConstructorUsedError; + Option get failureOrOption => + throw _privateConstructorUsedError; + Customer? get selectedCustomer => throw _privateConstructorUsedError; + bool get isFetching => throw _privateConstructorUsedError; + bool get hasReachedMax => throw _privateConstructorUsedError; + int get page => throw _privateConstructorUsedError; + + /// Create a copy of CustomerLoaderState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $CustomerLoaderStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CustomerLoaderStateCopyWith<$Res> { + factory $CustomerLoaderStateCopyWith( + CustomerLoaderState value, + $Res Function(CustomerLoaderState) then, + ) = _$CustomerLoaderStateCopyWithImpl<$Res, CustomerLoaderState>; + @useResult + $Res call({ + List customers, + Option failureOrOption, + Customer? selectedCustomer, + bool isFetching, + bool hasReachedMax, + int page, + }); + + $CustomerCopyWith<$Res>? get selectedCustomer; +} + +/// @nodoc +class _$CustomerLoaderStateCopyWithImpl<$Res, $Val extends CustomerLoaderState> + implements $CustomerLoaderStateCopyWith<$Res> { + _$CustomerLoaderStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CustomerLoaderState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? customers = null, + Object? failureOrOption = null, + Object? selectedCustomer = freezed, + Object? isFetching = null, + Object? hasReachedMax = null, + Object? page = null, + }) { + return _then( + _value.copyWith( + customers: null == customers + ? _value.customers + : customers // ignore: cast_nullable_to_non_nullable + as List, + failureOrOption: null == failureOrOption + ? _value.failureOrOption + : failureOrOption // ignore: cast_nullable_to_non_nullable + as Option, + selectedCustomer: freezed == selectedCustomer + ? _value.selectedCustomer + : selectedCustomer // ignore: cast_nullable_to_non_nullable + as Customer?, + 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, + ); + } + + /// Create a copy of CustomerLoaderState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $CustomerCopyWith<$Res>? get selectedCustomer { + if (_value.selectedCustomer == null) { + return null; + } + + return $CustomerCopyWith<$Res>(_value.selectedCustomer!, (value) { + return _then(_value.copyWith(selectedCustomer: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$CustomerLoaderStateImplCopyWith<$Res> + implements $CustomerLoaderStateCopyWith<$Res> { + factory _$$CustomerLoaderStateImplCopyWith( + _$CustomerLoaderStateImpl value, + $Res Function(_$CustomerLoaderStateImpl) then, + ) = __$$CustomerLoaderStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + List customers, + Option failureOrOption, + Customer? selectedCustomer, + bool isFetching, + bool hasReachedMax, + int page, + }); + + @override + $CustomerCopyWith<$Res>? get selectedCustomer; +} + +/// @nodoc +class __$$CustomerLoaderStateImplCopyWithImpl<$Res> + extends _$CustomerLoaderStateCopyWithImpl<$Res, _$CustomerLoaderStateImpl> + implements _$$CustomerLoaderStateImplCopyWith<$Res> { + __$$CustomerLoaderStateImplCopyWithImpl( + _$CustomerLoaderStateImpl _value, + $Res Function(_$CustomerLoaderStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerLoaderState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? customers = null, + Object? failureOrOption = null, + Object? selectedCustomer = freezed, + Object? isFetching = null, + Object? hasReachedMax = null, + Object? page = null, + }) { + return _then( + _$CustomerLoaderStateImpl( + customers: null == customers + ? _value._customers + : customers // ignore: cast_nullable_to_non_nullable + as List, + failureOrOption: null == failureOrOption + ? _value.failureOrOption + : failureOrOption // ignore: cast_nullable_to_non_nullable + as Option, + selectedCustomer: freezed == selectedCustomer + ? _value.selectedCustomer + : selectedCustomer // ignore: cast_nullable_to_non_nullable + as Customer?, + 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 _$CustomerLoaderStateImpl implements _CustomerLoaderState { + _$CustomerLoaderStateImpl({ + required final List customers, + required this.failureOrOption, + this.selectedCustomer, + this.isFetching = false, + this.hasReachedMax = false, + this.page = 1, + }) : _customers = customers; + + final List _customers; + @override + List get customers { + if (_customers is EqualUnmodifiableListView) return _customers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_customers); + } + + @override + final Option failureOrOption; + @override + final Customer? selectedCustomer; + @override + @JsonKey() + final bool isFetching; + @override + @JsonKey() + final bool hasReachedMax; + @override + @JsonKey() + final int page; + + @override + String toString() { + return 'CustomerLoaderState(customers: $customers, failureOrOption: $failureOrOption, selectedCustomer: $selectedCustomer, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CustomerLoaderStateImpl && + const DeepCollectionEquality().equals( + other._customers, + _customers, + ) && + (identical(other.failureOrOption, failureOrOption) || + other.failureOrOption == failureOrOption) && + (identical(other.selectedCustomer, selectedCustomer) || + other.selectedCustomer == selectedCustomer) && + (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(_customers), + failureOrOption, + selectedCustomer, + isFetching, + hasReachedMax, + page, + ); + + /// Create a copy of CustomerLoaderState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CustomerLoaderStateImplCopyWith<_$CustomerLoaderStateImpl> get copyWith => + __$$CustomerLoaderStateImplCopyWithImpl<_$CustomerLoaderStateImpl>( + this, + _$identity, + ); +} + +abstract class _CustomerLoaderState implements CustomerLoaderState { + factory _CustomerLoaderState({ + required final List customers, + required final Option failureOrOption, + final Customer? selectedCustomer, + final bool isFetching, + final bool hasReachedMax, + final int page, + }) = _$CustomerLoaderStateImpl; + + @override + List get customers; + @override + Option get failureOrOption; + @override + Customer? get selectedCustomer; + @override + bool get isFetching; + @override + bool get hasReachedMax; + @override + int get page; + + /// Create a copy of CustomerLoaderState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CustomerLoaderStateImplCopyWith<_$CustomerLoaderStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/application/customer/customer_loader/customer_loader_event.dart b/lib/application/customer/customer_loader/customer_loader_event.dart new file mode 100644 index 0000000..f1b7cb4 --- /dev/null +++ b/lib/application/customer/customer_loader/customer_loader_event.dart @@ -0,0 +1,9 @@ +part of 'customer_loader_bloc.dart'; + +@freezed +class CustomerLoaderEvent with _$CustomerLoaderEvent { + const factory CustomerLoaderEvent.setSelectedCustomer(Customer customer) = + _SetSelectedCustomer; + const factory CustomerLoaderEvent.fetched({@Default(false) bool isRefresh}) = + _Fetched; +} diff --git a/lib/application/customer/customer_loader/customer_loader_state.dart b/lib/application/customer/customer_loader/customer_loader_state.dart new file mode 100644 index 0000000..e3f4984 --- /dev/null +++ b/lib/application/customer/customer_loader/customer_loader_state.dart @@ -0,0 +1,16 @@ +part of 'customer_loader_bloc.dart'; + +@freezed +class CustomerLoaderState with _$CustomerLoaderState { + factory CustomerLoaderState({ + required List customers, + required Option failureOrOption, + Customer? selectedCustomer, + @Default(false) bool isFetching, + @Default(false) bool hasReachedMax, + @Default(1) int page, + }) = _CustomerLoaderState; + + factory CustomerLoaderState.initial() => + CustomerLoaderState(customers: [], failureOrOption: none()); +} diff --git a/lib/common/url/api_path.dart b/lib/common/url/api_path.dart index ab6fbd3..6e019c1 100644 --- a/lib/common/url/api_path.dart +++ b/lib/common/url/api_path.dart @@ -4,4 +4,5 @@ class ApiPath { static const String categories = '/api/v1/categories'; static const String products = '/api/v1/products'; static const String tables = '/api/v1/tables'; + static const String customers = '/api/v1/customers'; } diff --git a/lib/domain/customer/customer.dart b/lib/domain/customer/customer.dart new file mode 100644 index 0000000..7c5fbc5 --- /dev/null +++ b/lib/domain/customer/customer.dart @@ -0,0 +1,10 @@ +import 'package:dartz/dartz.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../../common/api/api_failure.dart'; + +part 'customer.freezed.dart'; + +part 'entities/customer_entity.dart'; +part 'failures/customer_failure.dart'; +part 'repositories/i_customer_repository.dart'; diff --git a/lib/domain/customer/customer.freezed.dart b/lib/domain/customer/customer.freezed.dart new file mode 100644 index 0000000..1decc9d --- /dev/null +++ b/lib/domain/customer/customer.freezed.dart @@ -0,0 +1,1452 @@ +// 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 'customer.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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 _$ListCustomer { + List get customers => throw _privateConstructorUsedError; + int get totalCount => throw _privateConstructorUsedError; + int get page => throw _privateConstructorUsedError; + int get limit => throw _privateConstructorUsedError; + int get totalPages => throw _privateConstructorUsedError; + + /// Create a copy of ListCustomer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ListCustomerCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ListCustomerCopyWith<$Res> { + factory $ListCustomerCopyWith( + ListCustomer value, + $Res Function(ListCustomer) then, + ) = _$ListCustomerCopyWithImpl<$Res, ListCustomer>; + @useResult + $Res call({ + List customers, + int totalCount, + int page, + int limit, + int totalPages, + }); +} + +/// @nodoc +class _$ListCustomerCopyWithImpl<$Res, $Val extends ListCustomer> + implements $ListCustomerCopyWith<$Res> { + _$ListCustomerCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ListCustomer + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? customers = null, + Object? totalCount = null, + Object? page = null, + Object? limit = null, + Object? totalPages = null, + }) { + return _then( + _value.copyWith( + customers: null == customers + ? _value.customers + : customers // ignore: cast_nullable_to_non_nullable + as List, + totalCount: null == totalCount + ? _value.totalCount + : totalCount // ignore: cast_nullable_to_non_nullable + as int, + page: null == page + ? _value.page + : page // ignore: cast_nullable_to_non_nullable + as int, + limit: null == limit + ? _value.limit + : limit // ignore: cast_nullable_to_non_nullable + as int, + totalPages: null == totalPages + ? _value.totalPages + : totalPages // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ListCustomerImplCopyWith<$Res> + implements $ListCustomerCopyWith<$Res> { + factory _$$ListCustomerImplCopyWith( + _$ListCustomerImpl value, + $Res Function(_$ListCustomerImpl) then, + ) = __$$ListCustomerImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + List customers, + int totalCount, + int page, + int limit, + int totalPages, + }); +} + +/// @nodoc +class __$$ListCustomerImplCopyWithImpl<$Res> + extends _$ListCustomerCopyWithImpl<$Res, _$ListCustomerImpl> + implements _$$ListCustomerImplCopyWith<$Res> { + __$$ListCustomerImplCopyWithImpl( + _$ListCustomerImpl _value, + $Res Function(_$ListCustomerImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ListCustomer + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? customers = null, + Object? totalCount = null, + Object? page = null, + Object? limit = null, + Object? totalPages = null, + }) { + return _then( + _$ListCustomerImpl( + customers: null == customers + ? _value._customers + : customers // ignore: cast_nullable_to_non_nullable + as List, + totalCount: null == totalCount + ? _value.totalCount + : totalCount // ignore: cast_nullable_to_non_nullable + as int, + page: null == page + ? _value.page + : page // ignore: cast_nullable_to_non_nullable + as int, + limit: null == limit + ? _value.limit + : limit // ignore: cast_nullable_to_non_nullable + as int, + totalPages: null == totalPages + ? _value.totalPages + : totalPages // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc + +class _$ListCustomerImpl implements _ListCustomer { + const _$ListCustomerImpl({ + required final List customers, + required this.totalCount, + required this.page, + required this.limit, + required this.totalPages, + }) : _customers = customers; + + final List _customers; + @override + List get customers { + if (_customers is EqualUnmodifiableListView) return _customers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_customers); + } + + @override + final int totalCount; + @override + final int page; + @override + final int limit; + @override + final int totalPages; + + @override + String toString() { + return 'ListCustomer(customers: $customers, totalCount: $totalCount, page: $page, limit: $limit, totalPages: $totalPages)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ListCustomerImpl && + const DeepCollectionEquality().equals( + other._customers, + _customers, + ) && + (identical(other.totalCount, totalCount) || + other.totalCount == totalCount) && + (identical(other.page, page) || other.page == page) && + (identical(other.limit, limit) || other.limit == limit) && + (identical(other.totalPages, totalPages) || + other.totalPages == totalPages)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_customers), + totalCount, + page, + limit, + totalPages, + ); + + /// Create a copy of ListCustomer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ListCustomerImplCopyWith<_$ListCustomerImpl> get copyWith => + __$$ListCustomerImplCopyWithImpl<_$ListCustomerImpl>(this, _$identity); +} + +abstract class _ListCustomer implements ListCustomer { + const factory _ListCustomer({ + required final List customers, + required final int totalCount, + required final int page, + required final int limit, + required final int totalPages, + }) = _$ListCustomerImpl; + + @override + List get customers; + @override + int get totalCount; + @override + int get page; + @override + int get limit; + @override + int get totalPages; + + /// Create a copy of ListCustomer + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ListCustomerImplCopyWith<_$ListCustomerImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$Customer { + String get id => throw _privateConstructorUsedError; + String get organizationId => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + String get email => throw _privateConstructorUsedError; + String get phone => throw _privateConstructorUsedError; + String get address => throw _privateConstructorUsedError; + bool get isDefault => throw _privateConstructorUsedError; + bool get isActive => throw _privateConstructorUsedError; + Map get metadata => throw _privateConstructorUsedError; + DateTime get createdAt => throw _privateConstructorUsedError; + DateTime get updatedAt => throw _privateConstructorUsedError; + + /// Create a copy of Customer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $CustomerCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CustomerCopyWith<$Res> { + factory $CustomerCopyWith(Customer value, $Res Function(Customer) then) = + _$CustomerCopyWithImpl<$Res, Customer>; + @useResult + $Res call({ + String id, + String organizationId, + String name, + String email, + String phone, + String address, + bool isDefault, + bool isActive, + Map metadata, + DateTime createdAt, + DateTime updatedAt, + }); +} + +/// @nodoc +class _$CustomerCopyWithImpl<$Res, $Val extends Customer> + implements $CustomerCopyWith<$Res> { + _$CustomerCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of Customer + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? organizationId = null, + Object? name = null, + Object? email = null, + Object? phone = null, + Object? address = null, + Object? isDefault = null, + Object? isActive = null, + Object? metadata = null, + Object? createdAt = null, + Object? updatedAt = null, + }) { + return _then( + _value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + organizationId: null == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + email: null == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String, + phone: null == phone + ? _value.phone + : phone // ignore: cast_nullable_to_non_nullable + as String, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + isDefault: null == isDefault + ? _value.isDefault + : isDefault // ignore: cast_nullable_to_non_nullable + as bool, + isActive: null == isActive + ? _value.isActive + : isActive // ignore: cast_nullable_to_non_nullable + as bool, + metadata: null == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Map, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$CustomerImplCopyWith<$Res> + implements $CustomerCopyWith<$Res> { + factory _$$CustomerImplCopyWith( + _$CustomerImpl value, + $Res Function(_$CustomerImpl) then, + ) = __$$CustomerImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String id, + String organizationId, + String name, + String email, + String phone, + String address, + bool isDefault, + bool isActive, + Map metadata, + DateTime createdAt, + DateTime updatedAt, + }); +} + +/// @nodoc +class __$$CustomerImplCopyWithImpl<$Res> + extends _$CustomerCopyWithImpl<$Res, _$CustomerImpl> + implements _$$CustomerImplCopyWith<$Res> { + __$$CustomerImplCopyWithImpl( + _$CustomerImpl _value, + $Res Function(_$CustomerImpl) _then, + ) : super(_value, _then); + + /// Create a copy of Customer + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? organizationId = null, + Object? name = null, + Object? email = null, + Object? phone = null, + Object? address = null, + Object? isDefault = null, + Object? isActive = null, + Object? metadata = null, + Object? createdAt = null, + Object? updatedAt = null, + }) { + return _then( + _$CustomerImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + organizationId: null == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + email: null == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String, + phone: null == phone + ? _value.phone + : phone // ignore: cast_nullable_to_non_nullable + as String, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + isDefault: null == isDefault + ? _value.isDefault + : isDefault // ignore: cast_nullable_to_non_nullable + as bool, + isActive: null == isActive + ? _value.isActive + : isActive // ignore: cast_nullable_to_non_nullable + as bool, + metadata: null == metadata + ? _value._metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Map, + createdAt: null == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as DateTime, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, + ), + ); + } +} + +/// @nodoc + +class _$CustomerImpl implements _Customer { + const _$CustomerImpl({ + required this.id, + required this.organizationId, + required this.name, + required this.email, + required this.phone, + required this.address, + required this.isDefault, + required this.isActive, + required final Map metadata, + required this.createdAt, + required this.updatedAt, + }) : _metadata = metadata; + + @override + final String id; + @override + final String organizationId; + @override + final String name; + @override + final String email; + @override + final String phone; + @override + final String address; + @override + final bool isDefault; + @override + final bool isActive; + final Map _metadata; + @override + Map get metadata { + if (_metadata is EqualUnmodifiableMapView) return _metadata; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_metadata); + } + + @override + final DateTime createdAt; + @override + final DateTime updatedAt; + + @override + String toString() { + return 'Customer(id: $id, organizationId: $organizationId, name: $name, email: $email, phone: $phone, address: $address, isDefault: $isDefault, isActive: $isActive, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CustomerImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.organizationId, organizationId) || + other.organizationId == organizationId) && + (identical(other.name, name) || other.name == name) && + (identical(other.email, email) || other.email == email) && + (identical(other.phone, phone) || other.phone == phone) && + (identical(other.address, address) || other.address == address) && + (identical(other.isDefault, isDefault) || + other.isDefault == isDefault) && + (identical(other.isActive, isActive) || + other.isActive == isActive) && + const DeepCollectionEquality().equals(other._metadata, _metadata) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + id, + organizationId, + name, + email, + phone, + address, + isDefault, + isActive, + const DeepCollectionEquality().hash(_metadata), + createdAt, + updatedAt, + ); + + /// Create a copy of Customer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CustomerImplCopyWith<_$CustomerImpl> get copyWith => + __$$CustomerImplCopyWithImpl<_$CustomerImpl>(this, _$identity); +} + +abstract class _Customer implements Customer { + const factory _Customer({ + required final String id, + required final String organizationId, + required final String name, + required final String email, + required final String phone, + required final String address, + required final bool isDefault, + required final bool isActive, + required final Map metadata, + required final DateTime createdAt, + required final DateTime updatedAt, + }) = _$CustomerImpl; + + @override + String get id; + @override + String get organizationId; + @override + String get name; + @override + String get email; + @override + String get phone; + @override + String get address; + @override + bool get isDefault; + @override + bool get isActive; + @override + Map get metadata; + @override + DateTime get createdAt; + @override + DateTime get updatedAt; + + /// Create a copy of Customer + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CustomerImplCopyWith<_$CustomerImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$CustomerFailure { + @optionalTypeArgs + TResult when({ + required TResult Function(ApiFailure failure) serverError, + required TResult Function() unexpectedError, + required TResult Function() empty, + required TResult Function(String erroMessage) localStorageError, + required TResult Function(String erroMessage) dynamicErrorMessage, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(ApiFailure failure)? serverError, + TResult? Function()? unexpectedError, + TResult? Function()? empty, + TResult? Function(String erroMessage)? localStorageError, + TResult? Function(String erroMessage)? dynamicErrorMessage, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(ApiFailure failure)? serverError, + TResult Function()? unexpectedError, + TResult Function()? empty, + TResult Function(String erroMessage)? localStorageError, + TResult Function(String erroMessage)? dynamicErrorMessage, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_ServerError value) serverError, + required TResult Function(_UnexpectedError value) unexpectedError, + required TResult Function(_Empty value) empty, + required TResult Function(_LocalStorageError value) localStorageError, + required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_ServerError value)? serverError, + TResult? Function(_UnexpectedError value)? unexpectedError, + TResult? Function(_Empty value)? empty, + TResult? Function(_LocalStorageError value)? localStorageError, + TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_ServerError value)? serverError, + TResult Function(_UnexpectedError value)? unexpectedError, + TResult Function(_Empty value)? empty, + TResult Function(_LocalStorageError value)? localStorageError, + TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CustomerFailureCopyWith<$Res> { + factory $CustomerFailureCopyWith( + CustomerFailure value, + $Res Function(CustomerFailure) then, + ) = _$CustomerFailureCopyWithImpl<$Res, CustomerFailure>; +} + +/// @nodoc +class _$CustomerFailureCopyWithImpl<$Res, $Val extends CustomerFailure> + implements $CustomerFailureCopyWith<$Res> { + _$CustomerFailureCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$ServerErrorImplCopyWith<$Res> { + factory _$$ServerErrorImplCopyWith( + _$ServerErrorImpl value, + $Res Function(_$ServerErrorImpl) then, + ) = __$$ServerErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({ApiFailure failure}); + + $ApiFailureCopyWith<$Res> get failure; +} + +/// @nodoc +class __$$ServerErrorImplCopyWithImpl<$Res> + extends _$CustomerFailureCopyWithImpl<$Res, _$ServerErrorImpl> + implements _$$ServerErrorImplCopyWith<$Res> { + __$$ServerErrorImplCopyWithImpl( + _$ServerErrorImpl _value, + $Res Function(_$ServerErrorImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? failure = null}) { + return _then( + _$ServerErrorImpl( + null == failure + ? _value.failure + : failure // ignore: cast_nullable_to_non_nullable + as ApiFailure, + ), + ); + } + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ApiFailureCopyWith<$Res> get failure { + return $ApiFailureCopyWith<$Res>(_value.failure, (value) { + return _then(_value.copyWith(failure: value)); + }); + } +} + +/// @nodoc + +class _$ServerErrorImpl implements _ServerError { + const _$ServerErrorImpl(this.failure); + + @override + final ApiFailure failure; + + @override + String toString() { + return 'CustomerFailure.serverError(failure: $failure)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ServerErrorImpl && + (identical(other.failure, failure) || other.failure == failure)); + } + + @override + int get hashCode => Object.hash(runtimeType, failure); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ServerErrorImplCopyWith<_$ServerErrorImpl> get copyWith => + __$$ServerErrorImplCopyWithImpl<_$ServerErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(ApiFailure failure) serverError, + required TResult Function() unexpectedError, + required TResult Function() empty, + required TResult Function(String erroMessage) localStorageError, + required TResult Function(String erroMessage) dynamicErrorMessage, + }) { + return serverError(failure); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(ApiFailure failure)? serverError, + TResult? Function()? unexpectedError, + TResult? Function()? empty, + TResult? Function(String erroMessage)? localStorageError, + TResult? Function(String erroMessage)? dynamicErrorMessage, + }) { + return serverError?.call(failure); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(ApiFailure failure)? serverError, + TResult Function()? unexpectedError, + TResult Function()? empty, + TResult Function(String erroMessage)? localStorageError, + TResult Function(String erroMessage)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (serverError != null) { + return serverError(failure); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_ServerError value) serverError, + required TResult Function(_UnexpectedError value) unexpectedError, + required TResult Function(_Empty value) empty, + required TResult Function(_LocalStorageError value) localStorageError, + required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage, + }) { + return serverError(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_ServerError value)? serverError, + TResult? Function(_UnexpectedError value)? unexpectedError, + TResult? Function(_Empty value)? empty, + TResult? Function(_LocalStorageError value)? localStorageError, + TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage, + }) { + return serverError?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_ServerError value)? serverError, + TResult Function(_UnexpectedError value)? unexpectedError, + TResult Function(_Empty value)? empty, + TResult Function(_LocalStorageError value)? localStorageError, + TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (serverError != null) { + return serverError(this); + } + return orElse(); + } +} + +abstract class _ServerError implements CustomerFailure { + const factory _ServerError(final ApiFailure failure) = _$ServerErrorImpl; + + ApiFailure get failure; + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ServerErrorImplCopyWith<_$ServerErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$UnexpectedErrorImplCopyWith<$Res> { + factory _$$UnexpectedErrorImplCopyWith( + _$UnexpectedErrorImpl value, + $Res Function(_$UnexpectedErrorImpl) then, + ) = __$$UnexpectedErrorImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$UnexpectedErrorImplCopyWithImpl<$Res> + extends _$CustomerFailureCopyWithImpl<$Res, _$UnexpectedErrorImpl> + implements _$$UnexpectedErrorImplCopyWith<$Res> { + __$$UnexpectedErrorImplCopyWithImpl( + _$UnexpectedErrorImpl _value, + $Res Function(_$UnexpectedErrorImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$UnexpectedErrorImpl implements _UnexpectedError { + const _$UnexpectedErrorImpl(); + + @override + String toString() { + return 'CustomerFailure.unexpectedError()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$UnexpectedErrorImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(ApiFailure failure) serverError, + required TResult Function() unexpectedError, + required TResult Function() empty, + required TResult Function(String erroMessage) localStorageError, + required TResult Function(String erroMessage) dynamicErrorMessage, + }) { + return unexpectedError(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(ApiFailure failure)? serverError, + TResult? Function()? unexpectedError, + TResult? Function()? empty, + TResult? Function(String erroMessage)? localStorageError, + TResult? Function(String erroMessage)? dynamicErrorMessage, + }) { + return unexpectedError?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(ApiFailure failure)? serverError, + TResult Function()? unexpectedError, + TResult Function()? empty, + TResult Function(String erroMessage)? localStorageError, + TResult Function(String erroMessage)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (unexpectedError != null) { + return unexpectedError(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_ServerError value) serverError, + required TResult Function(_UnexpectedError value) unexpectedError, + required TResult Function(_Empty value) empty, + required TResult Function(_LocalStorageError value) localStorageError, + required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage, + }) { + return unexpectedError(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_ServerError value)? serverError, + TResult? Function(_UnexpectedError value)? unexpectedError, + TResult? Function(_Empty value)? empty, + TResult? Function(_LocalStorageError value)? localStorageError, + TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage, + }) { + return unexpectedError?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_ServerError value)? serverError, + TResult Function(_UnexpectedError value)? unexpectedError, + TResult Function(_Empty value)? empty, + TResult Function(_LocalStorageError value)? localStorageError, + TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (unexpectedError != null) { + return unexpectedError(this); + } + return orElse(); + } +} + +abstract class _UnexpectedError implements CustomerFailure { + const factory _UnexpectedError() = _$UnexpectedErrorImpl; +} + +/// @nodoc +abstract class _$$EmptyImplCopyWith<$Res> { + factory _$$EmptyImplCopyWith( + _$EmptyImpl value, + $Res Function(_$EmptyImpl) then, + ) = __$$EmptyImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$EmptyImplCopyWithImpl<$Res> + extends _$CustomerFailureCopyWithImpl<$Res, _$EmptyImpl> + implements _$$EmptyImplCopyWith<$Res> { + __$$EmptyImplCopyWithImpl( + _$EmptyImpl _value, + $Res Function(_$EmptyImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$EmptyImpl implements _Empty { + const _$EmptyImpl(); + + @override + String toString() { + return 'CustomerFailure.empty()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$EmptyImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(ApiFailure failure) serverError, + required TResult Function() unexpectedError, + required TResult Function() empty, + required TResult Function(String erroMessage) localStorageError, + required TResult Function(String erroMessage) dynamicErrorMessage, + }) { + return empty(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(ApiFailure failure)? serverError, + TResult? Function()? unexpectedError, + TResult? Function()? empty, + TResult? Function(String erroMessage)? localStorageError, + TResult? Function(String erroMessage)? dynamicErrorMessage, + }) { + return empty?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(ApiFailure failure)? serverError, + TResult Function()? unexpectedError, + TResult Function()? empty, + TResult Function(String erroMessage)? localStorageError, + TResult Function(String erroMessage)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (empty != null) { + return empty(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_ServerError value) serverError, + required TResult Function(_UnexpectedError value) unexpectedError, + required TResult Function(_Empty value) empty, + required TResult Function(_LocalStorageError value) localStorageError, + required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage, + }) { + return empty(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_ServerError value)? serverError, + TResult? Function(_UnexpectedError value)? unexpectedError, + TResult? Function(_Empty value)? empty, + TResult? Function(_LocalStorageError value)? localStorageError, + TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage, + }) { + return empty?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_ServerError value)? serverError, + TResult Function(_UnexpectedError value)? unexpectedError, + TResult Function(_Empty value)? empty, + TResult Function(_LocalStorageError value)? localStorageError, + TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (empty != null) { + return empty(this); + } + return orElse(); + } +} + +abstract class _Empty implements CustomerFailure { + const factory _Empty() = _$EmptyImpl; +} + +/// @nodoc +abstract class _$$LocalStorageErrorImplCopyWith<$Res> { + factory _$$LocalStorageErrorImplCopyWith( + _$LocalStorageErrorImpl value, + $Res Function(_$LocalStorageErrorImpl) then, + ) = __$$LocalStorageErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String erroMessage}); +} + +/// @nodoc +class __$$LocalStorageErrorImplCopyWithImpl<$Res> + extends _$CustomerFailureCopyWithImpl<$Res, _$LocalStorageErrorImpl> + implements _$$LocalStorageErrorImplCopyWith<$Res> { + __$$LocalStorageErrorImplCopyWithImpl( + _$LocalStorageErrorImpl _value, + $Res Function(_$LocalStorageErrorImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? erroMessage = null}) { + return _then( + _$LocalStorageErrorImpl( + null == erroMessage + ? _value.erroMessage + : erroMessage // ignore: cast_nullable_to_non_nullable + as String, + ), + ); + } +} + +/// @nodoc + +class _$LocalStorageErrorImpl implements _LocalStorageError { + const _$LocalStorageErrorImpl(this.erroMessage); + + @override + final String erroMessage; + + @override + String toString() { + return 'CustomerFailure.localStorageError(erroMessage: $erroMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LocalStorageErrorImpl && + (identical(other.erroMessage, erroMessage) || + other.erroMessage == erroMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, erroMessage); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$LocalStorageErrorImplCopyWith<_$LocalStorageErrorImpl> get copyWith => + __$$LocalStorageErrorImplCopyWithImpl<_$LocalStorageErrorImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(ApiFailure failure) serverError, + required TResult Function() unexpectedError, + required TResult Function() empty, + required TResult Function(String erroMessage) localStorageError, + required TResult Function(String erroMessage) dynamicErrorMessage, + }) { + return localStorageError(erroMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(ApiFailure failure)? serverError, + TResult? Function()? unexpectedError, + TResult? Function()? empty, + TResult? Function(String erroMessage)? localStorageError, + TResult? Function(String erroMessage)? dynamicErrorMessage, + }) { + return localStorageError?.call(erroMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(ApiFailure failure)? serverError, + TResult Function()? unexpectedError, + TResult Function()? empty, + TResult Function(String erroMessage)? localStorageError, + TResult Function(String erroMessage)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (localStorageError != null) { + return localStorageError(erroMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_ServerError value) serverError, + required TResult Function(_UnexpectedError value) unexpectedError, + required TResult Function(_Empty value) empty, + required TResult Function(_LocalStorageError value) localStorageError, + required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage, + }) { + return localStorageError(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_ServerError value)? serverError, + TResult? Function(_UnexpectedError value)? unexpectedError, + TResult? Function(_Empty value)? empty, + TResult? Function(_LocalStorageError value)? localStorageError, + TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage, + }) { + return localStorageError?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_ServerError value)? serverError, + TResult Function(_UnexpectedError value)? unexpectedError, + TResult Function(_Empty value)? empty, + TResult Function(_LocalStorageError value)? localStorageError, + TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (localStorageError != null) { + return localStorageError(this); + } + return orElse(); + } +} + +abstract class _LocalStorageError implements CustomerFailure { + const factory _LocalStorageError(final String erroMessage) = + _$LocalStorageErrorImpl; + + String get erroMessage; + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$LocalStorageErrorImplCopyWith<_$LocalStorageErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$DynamicErrorMessageImplCopyWith<$Res> { + factory _$$DynamicErrorMessageImplCopyWith( + _$DynamicErrorMessageImpl value, + $Res Function(_$DynamicErrorMessageImpl) then, + ) = __$$DynamicErrorMessageImplCopyWithImpl<$Res>; + @useResult + $Res call({String erroMessage}); +} + +/// @nodoc +class __$$DynamicErrorMessageImplCopyWithImpl<$Res> + extends _$CustomerFailureCopyWithImpl<$Res, _$DynamicErrorMessageImpl> + implements _$$DynamicErrorMessageImplCopyWith<$Res> { + __$$DynamicErrorMessageImplCopyWithImpl( + _$DynamicErrorMessageImpl _value, + $Res Function(_$DynamicErrorMessageImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? erroMessage = null}) { + return _then( + _$DynamicErrorMessageImpl( + null == erroMessage + ? _value.erroMessage + : erroMessage // ignore: cast_nullable_to_non_nullable + as String, + ), + ); + } +} + +/// @nodoc + +class _$DynamicErrorMessageImpl implements _DynamicErrorMessage { + const _$DynamicErrorMessageImpl(this.erroMessage); + + @override + final String erroMessage; + + @override + String toString() { + return 'CustomerFailure.dynamicErrorMessage(erroMessage: $erroMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DynamicErrorMessageImpl && + (identical(other.erroMessage, erroMessage) || + other.erroMessage == erroMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, erroMessage); + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$DynamicErrorMessageImplCopyWith<_$DynamicErrorMessageImpl> get copyWith => + __$$DynamicErrorMessageImplCopyWithImpl<_$DynamicErrorMessageImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(ApiFailure failure) serverError, + required TResult Function() unexpectedError, + required TResult Function() empty, + required TResult Function(String erroMessage) localStorageError, + required TResult Function(String erroMessage) dynamicErrorMessage, + }) { + return dynamicErrorMessage(erroMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(ApiFailure failure)? serverError, + TResult? Function()? unexpectedError, + TResult? Function()? empty, + TResult? Function(String erroMessage)? localStorageError, + TResult? Function(String erroMessage)? dynamicErrorMessage, + }) { + return dynamicErrorMessage?.call(erroMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(ApiFailure failure)? serverError, + TResult Function()? unexpectedError, + TResult Function()? empty, + TResult Function(String erroMessage)? localStorageError, + TResult Function(String erroMessage)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (dynamicErrorMessage != null) { + return dynamicErrorMessage(erroMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_ServerError value) serverError, + required TResult Function(_UnexpectedError value) unexpectedError, + required TResult Function(_Empty value) empty, + required TResult Function(_LocalStorageError value) localStorageError, + required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage, + }) { + return dynamicErrorMessage(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_ServerError value)? serverError, + TResult? Function(_UnexpectedError value)? unexpectedError, + TResult? Function(_Empty value)? empty, + TResult? Function(_LocalStorageError value)? localStorageError, + TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage, + }) { + return dynamicErrorMessage?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_ServerError value)? serverError, + TResult Function(_UnexpectedError value)? unexpectedError, + TResult Function(_Empty value)? empty, + TResult Function(_LocalStorageError value)? localStorageError, + TResult Function(_DynamicErrorMessage value)? dynamicErrorMessage, + required TResult orElse(), + }) { + if (dynamicErrorMessage != null) { + return dynamicErrorMessage(this); + } + return orElse(); + } +} + +abstract class _DynamicErrorMessage implements CustomerFailure { + const factory _DynamicErrorMessage(final String erroMessage) = + _$DynamicErrorMessageImpl; + + String get erroMessage; + + /// Create a copy of CustomerFailure + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$DynamicErrorMessageImplCopyWith<_$DynamicErrorMessageImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/domain/customer/entities/customer_entity.dart b/lib/domain/customer/entities/customer_entity.dart new file mode 100644 index 0000000..45f9ecd --- /dev/null +++ b/lib/domain/customer/entities/customer_entity.dart @@ -0,0 +1,51 @@ +part of '../customer.dart'; + +@freezed +class ListCustomer with _$ListCustomer { + const factory ListCustomer({ + required List customers, + required int totalCount, + required int page, + required int limit, + required int totalPages, + }) = _ListCustomer; + + factory ListCustomer.empty() => ListCustomer( + customers: const [], + totalCount: 0, + page: 0, + limit: 0, + totalPages: 0, + ); +} + +@freezed +class Customer with _$Customer { + const factory Customer({ + required String id, + required String organizationId, + required String name, + required String email, + required String phone, + required String address, + required bool isDefault, + required bool isActive, + required Map metadata, + required DateTime createdAt, + required DateTime updatedAt, + }) = _Customer; + + factory Customer.empty() => Customer( + id: '', + organizationId: '', + name: '', + email: '', + phone: '', + address: '', + isDefault: false, + isActive: false, + metadata: const {}, + createdAt: DateTime(1970), + updatedAt: DateTime(1970), + ); +} diff --git a/lib/domain/customer/failures/customer_failure.dart b/lib/domain/customer/failures/customer_failure.dart new file mode 100644 index 0000000..1be3ebc --- /dev/null +++ b/lib/domain/customer/failures/customer_failure.dart @@ -0,0 +1,12 @@ +part of '../customer.dart'; + +@freezed +sealed class CustomerFailure with _$CustomerFailure { + const factory CustomerFailure.serverError(ApiFailure failure) = _ServerError; + const factory CustomerFailure.unexpectedError() = _UnexpectedError; + const factory CustomerFailure.empty() = _Empty; + const factory CustomerFailure.localStorageError(String erroMessage) = + _LocalStorageError; + const factory CustomerFailure.dynamicErrorMessage(String erroMessage) = + _DynamicErrorMessage; +} diff --git a/lib/domain/customer/repositories/i_customer_repository.dart b/lib/domain/customer/repositories/i_customer_repository.dart new file mode 100644 index 0000000..87fe1b8 --- /dev/null +++ b/lib/domain/customer/repositories/i_customer_repository.dart @@ -0,0 +1,8 @@ +part of '../customer.dart'; + +abstract class ICustomerRepository { + Future> getCustomer({ + int page = 1, + int limit = 10, + }); +} diff --git a/lib/infrastructure/customer/customer_dtos.dart b/lib/infrastructure/customer/customer_dtos.dart new file mode 100644 index 0000000..287b0c0 --- /dev/null +++ b/lib/infrastructure/customer/customer_dtos.dart @@ -0,0 +1,9 @@ +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../../domain/customer/customer.dart'; + +part 'customer_dtos.freezed.dart'; +part 'customer_dtos.g.dart'; + +part 'dtos/customer_dto.dart'; diff --git a/lib/infrastructure/customer/customer_dtos.freezed.dart b/lib/infrastructure/customer/customer_dtos.freezed.dart new file mode 100644 index 0000000..b96e9ef --- /dev/null +++ b/lib/infrastructure/customer/customer_dtos.freezed.dart @@ -0,0 +1,754 @@ +// 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 'customer_dtos.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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', +); + +ListCustomerDto _$ListCustomerDtoFromJson(Map json) { + return _ListCustomerDto.fromJson(json); +} + +/// @nodoc +mixin _$ListCustomerDto { + @JsonKey(name: "data") + List? get customers => throw _privateConstructorUsedError; + @JsonKey(name: "total_count") + int? get totalCount => throw _privateConstructorUsedError; + @JsonKey(name: "page") + int? get page => throw _privateConstructorUsedError; + @JsonKey(name: "limit") + int? get limit => throw _privateConstructorUsedError; + @JsonKey(name: "total_pages") + int? get totalPages => throw _privateConstructorUsedError; + + /// Serializes this ListCustomerDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ListCustomerDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ListCustomerDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ListCustomerDtoCopyWith<$Res> { + factory $ListCustomerDtoCopyWith( + ListCustomerDto value, + $Res Function(ListCustomerDto) then, + ) = _$ListCustomerDtoCopyWithImpl<$Res, ListCustomerDto>; + @useResult + $Res call({ + @JsonKey(name: "data") List? customers, + @JsonKey(name: "total_count") int? totalCount, + @JsonKey(name: "page") int? page, + @JsonKey(name: "limit") int? limit, + @JsonKey(name: "total_pages") int? totalPages, + }); +} + +/// @nodoc +class _$ListCustomerDtoCopyWithImpl<$Res, $Val extends ListCustomerDto> + implements $ListCustomerDtoCopyWith<$Res> { + _$ListCustomerDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ListCustomerDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? customers = freezed, + Object? totalCount = freezed, + Object? page = freezed, + Object? limit = freezed, + Object? totalPages = freezed, + }) { + return _then( + _value.copyWith( + customers: freezed == customers + ? _value.customers + : customers // ignore: cast_nullable_to_non_nullable + as List?, + totalCount: freezed == totalCount + ? _value.totalCount + : totalCount // ignore: cast_nullable_to_non_nullable + as int?, + page: freezed == page + ? _value.page + : page // ignore: cast_nullable_to_non_nullable + as int?, + limit: freezed == limit + ? _value.limit + : limit // ignore: cast_nullable_to_non_nullable + as int?, + totalPages: freezed == totalPages + ? _value.totalPages + : totalPages // ignore: cast_nullable_to_non_nullable + as int?, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ListCustomerDtoImplCopyWith<$Res> + implements $ListCustomerDtoCopyWith<$Res> { + factory _$$ListCustomerDtoImplCopyWith( + _$ListCustomerDtoImpl value, + $Res Function(_$ListCustomerDtoImpl) then, + ) = __$$ListCustomerDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: "data") List? customers, + @JsonKey(name: "total_count") int? totalCount, + @JsonKey(name: "page") int? page, + @JsonKey(name: "limit") int? limit, + @JsonKey(name: "total_pages") int? totalPages, + }); +} + +/// @nodoc +class __$$ListCustomerDtoImplCopyWithImpl<$Res> + extends _$ListCustomerDtoCopyWithImpl<$Res, _$ListCustomerDtoImpl> + implements _$$ListCustomerDtoImplCopyWith<$Res> { + __$$ListCustomerDtoImplCopyWithImpl( + _$ListCustomerDtoImpl _value, + $Res Function(_$ListCustomerDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ListCustomerDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? customers = freezed, + Object? totalCount = freezed, + Object? page = freezed, + Object? limit = freezed, + Object? totalPages = freezed, + }) { + return _then( + _$ListCustomerDtoImpl( + customers: freezed == customers + ? _value._customers + : customers // ignore: cast_nullable_to_non_nullable + as List?, + totalCount: freezed == totalCount + ? _value.totalCount + : totalCount // ignore: cast_nullable_to_non_nullable + as int?, + page: freezed == page + ? _value.page + : page // ignore: cast_nullable_to_non_nullable + as int?, + limit: freezed == limit + ? _value.limit + : limit // ignore: cast_nullable_to_non_nullable + as int?, + totalPages: freezed == totalPages + ? _value.totalPages + : totalPages // ignore: cast_nullable_to_non_nullable + as int?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$ListCustomerDtoImpl extends _ListCustomerDto + with DiagnosticableTreeMixin { + const _$ListCustomerDtoImpl({ + @JsonKey(name: "data") final List? customers, + @JsonKey(name: "total_count") this.totalCount, + @JsonKey(name: "page") this.page, + @JsonKey(name: "limit") this.limit, + @JsonKey(name: "total_pages") this.totalPages, + }) : _customers = customers, + super._(); + + factory _$ListCustomerDtoImpl.fromJson(Map json) => + _$$ListCustomerDtoImplFromJson(json); + + final List? _customers; + @override + @JsonKey(name: "data") + List? get customers { + final value = _customers; + if (value == null) return null; + if (_customers is EqualUnmodifiableListView) return _customers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + @JsonKey(name: "total_count") + final int? totalCount; + @override + @JsonKey(name: "page") + final int? page; + @override + @JsonKey(name: "limit") + final int? limit; + @override + @JsonKey(name: "total_pages") + final int? totalPages; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'ListCustomerDto(customers: $customers, totalCount: $totalCount, page: $page, limit: $limit, totalPages: $totalPages)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'ListCustomerDto')) + ..add(DiagnosticsProperty('customers', customers)) + ..add(DiagnosticsProperty('totalCount', totalCount)) + ..add(DiagnosticsProperty('page', page)) + ..add(DiagnosticsProperty('limit', limit)) + ..add(DiagnosticsProperty('totalPages', totalPages)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ListCustomerDtoImpl && + const DeepCollectionEquality().equals( + other._customers, + _customers, + ) && + (identical(other.totalCount, totalCount) || + other.totalCount == totalCount) && + (identical(other.page, page) || other.page == page) && + (identical(other.limit, limit) || other.limit == limit) && + (identical(other.totalPages, totalPages) || + other.totalPages == totalPages)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_customers), + totalCount, + page, + limit, + totalPages, + ); + + /// Create a copy of ListCustomerDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ListCustomerDtoImplCopyWith<_$ListCustomerDtoImpl> get copyWith => + __$$ListCustomerDtoImplCopyWithImpl<_$ListCustomerDtoImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$ListCustomerDtoImplToJson(this); + } +} + +abstract class _ListCustomerDto extends ListCustomerDto { + const factory _ListCustomerDto({ + @JsonKey(name: "data") final List? customers, + @JsonKey(name: "total_count") final int? totalCount, + @JsonKey(name: "page") final int? page, + @JsonKey(name: "limit") final int? limit, + @JsonKey(name: "total_pages") final int? totalPages, + }) = _$ListCustomerDtoImpl; + const _ListCustomerDto._() : super._(); + + factory _ListCustomerDto.fromJson(Map json) = + _$ListCustomerDtoImpl.fromJson; + + @override + @JsonKey(name: "data") + List? get customers; + @override + @JsonKey(name: "total_count") + int? get totalCount; + @override + @JsonKey(name: "page") + int? get page; + @override + @JsonKey(name: "limit") + int? get limit; + @override + @JsonKey(name: "total_pages") + int? get totalPages; + + /// Create a copy of ListCustomerDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ListCustomerDtoImplCopyWith<_$ListCustomerDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +CustomerDto _$CustomerDtoFromJson(Map json) { + return _CustomerDto.fromJson(json); +} + +/// @nodoc +mixin _$CustomerDto { + @JsonKey(name: "id") + String? get id => throw _privateConstructorUsedError; + @JsonKey(name: "organization_id") + String? get organizationId => throw _privateConstructorUsedError; + @JsonKey(name: "name") + String? get name => throw _privateConstructorUsedError; + @JsonKey(name: "email") + String? get email => throw _privateConstructorUsedError; + @JsonKey(name: "phone") + String? get phone => throw _privateConstructorUsedError; + @JsonKey(name: "address") + String? get address => throw _privateConstructorUsedError; + @JsonKey(name: "is_default") + bool? get isDefault => throw _privateConstructorUsedError; + @JsonKey(name: "is_active") + bool? get isActive => throw _privateConstructorUsedError; + @JsonKey(name: "metadata") + Map? get metadata => throw _privateConstructorUsedError; + @JsonKey(name: "created_at") + String? get createdAt => throw _privateConstructorUsedError; + @JsonKey(name: "updated_at") + String? get updatedAt => throw _privateConstructorUsedError; + + /// Serializes this CustomerDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of CustomerDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $CustomerDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CustomerDtoCopyWith<$Res> { + factory $CustomerDtoCopyWith( + CustomerDto value, + $Res Function(CustomerDto) then, + ) = _$CustomerDtoCopyWithImpl<$Res, CustomerDto>; + @useResult + $Res call({ + @JsonKey(name: "id") String? id, + @JsonKey(name: "organization_id") String? organizationId, + @JsonKey(name: "name") String? name, + @JsonKey(name: "email") String? email, + @JsonKey(name: "phone") String? phone, + @JsonKey(name: "address") String? address, + @JsonKey(name: "is_default") bool? isDefault, + @JsonKey(name: "is_active") bool? isActive, + @JsonKey(name: "metadata") Map? metadata, + @JsonKey(name: "created_at") String? createdAt, + @JsonKey(name: "updated_at") String? updatedAt, + }); +} + +/// @nodoc +class _$CustomerDtoCopyWithImpl<$Res, $Val extends CustomerDto> + implements $CustomerDtoCopyWith<$Res> { + _$CustomerDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CustomerDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? organizationId = freezed, + Object? name = freezed, + Object? email = freezed, + Object? phone = freezed, + Object? address = freezed, + Object? isDefault = freezed, + Object? isActive = freezed, + Object? metadata = freezed, + Object? createdAt = freezed, + Object? updatedAt = freezed, + }) { + return _then( + _value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + organizationId: freezed == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String?, + name: freezed == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String?, + email: freezed == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String?, + phone: freezed == phone + ? _value.phone + : phone // ignore: cast_nullable_to_non_nullable + as String?, + address: freezed == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String?, + isDefault: freezed == isDefault + ? _value.isDefault + : isDefault // ignore: cast_nullable_to_non_nullable + as bool?, + isActive: freezed == isActive + ? _value.isActive + : isActive // ignore: cast_nullable_to_non_nullable + as bool?, + metadata: freezed == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Map?, + createdAt: freezed == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as String?, + updatedAt: freezed == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as String?, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$CustomerDtoImplCopyWith<$Res> + implements $CustomerDtoCopyWith<$Res> { + factory _$$CustomerDtoImplCopyWith( + _$CustomerDtoImpl value, + $Res Function(_$CustomerDtoImpl) then, + ) = __$$CustomerDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: "id") String? id, + @JsonKey(name: "organization_id") String? organizationId, + @JsonKey(name: "name") String? name, + @JsonKey(name: "email") String? email, + @JsonKey(name: "phone") String? phone, + @JsonKey(name: "address") String? address, + @JsonKey(name: "is_default") bool? isDefault, + @JsonKey(name: "is_active") bool? isActive, + @JsonKey(name: "metadata") Map? metadata, + @JsonKey(name: "created_at") String? createdAt, + @JsonKey(name: "updated_at") String? updatedAt, + }); +} + +/// @nodoc +class __$$CustomerDtoImplCopyWithImpl<$Res> + extends _$CustomerDtoCopyWithImpl<$Res, _$CustomerDtoImpl> + implements _$$CustomerDtoImplCopyWith<$Res> { + __$$CustomerDtoImplCopyWithImpl( + _$CustomerDtoImpl _value, + $Res Function(_$CustomerDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CustomerDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? organizationId = freezed, + Object? name = freezed, + Object? email = freezed, + Object? phone = freezed, + Object? address = freezed, + Object? isDefault = freezed, + Object? isActive = freezed, + Object? metadata = freezed, + Object? createdAt = freezed, + Object? updatedAt = freezed, + }) { + return _then( + _$CustomerDtoImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + organizationId: freezed == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String?, + name: freezed == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String?, + email: freezed == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String?, + phone: freezed == phone + ? _value.phone + : phone // ignore: cast_nullable_to_non_nullable + as String?, + address: freezed == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String?, + isDefault: freezed == isDefault + ? _value.isDefault + : isDefault // ignore: cast_nullable_to_non_nullable + as bool?, + isActive: freezed == isActive + ? _value.isActive + : isActive // ignore: cast_nullable_to_non_nullable + as bool?, + metadata: freezed == metadata + ? _value._metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Map?, + createdAt: freezed == createdAt + ? _value.createdAt + : createdAt // ignore: cast_nullable_to_non_nullable + as String?, + updatedAt: freezed == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as String?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$CustomerDtoImpl extends _CustomerDto with DiagnosticableTreeMixin { + const _$CustomerDtoImpl({ + @JsonKey(name: "id") this.id, + @JsonKey(name: "organization_id") this.organizationId, + @JsonKey(name: "name") this.name, + @JsonKey(name: "email") this.email, + @JsonKey(name: "phone") this.phone, + @JsonKey(name: "address") this.address, + @JsonKey(name: "is_default") this.isDefault, + @JsonKey(name: "is_active") this.isActive, + @JsonKey(name: "metadata") final Map? metadata, + @JsonKey(name: "created_at") this.createdAt, + @JsonKey(name: "updated_at") this.updatedAt, + }) : _metadata = metadata, + super._(); + + factory _$CustomerDtoImpl.fromJson(Map json) => + _$$CustomerDtoImplFromJson(json); + + @override + @JsonKey(name: "id") + final String? id; + @override + @JsonKey(name: "organization_id") + final String? organizationId; + @override + @JsonKey(name: "name") + final String? name; + @override + @JsonKey(name: "email") + final String? email; + @override + @JsonKey(name: "phone") + final String? phone; + @override + @JsonKey(name: "address") + final String? address; + @override + @JsonKey(name: "is_default") + final bool? isDefault; + @override + @JsonKey(name: "is_active") + final bool? isActive; + final Map? _metadata; + @override + @JsonKey(name: "metadata") + Map? get metadata { + final value = _metadata; + if (value == null) return null; + if (_metadata is EqualUnmodifiableMapView) return _metadata; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + + @override + @JsonKey(name: "created_at") + final String? createdAt; + @override + @JsonKey(name: "updated_at") + final String? updatedAt; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'CustomerDto(id: $id, organizationId: $organizationId, name: $name, email: $email, phone: $phone, address: $address, isDefault: $isDefault, isActive: $isActive, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'CustomerDto')) + ..add(DiagnosticsProperty('id', id)) + ..add(DiagnosticsProperty('organizationId', organizationId)) + ..add(DiagnosticsProperty('name', name)) + ..add(DiagnosticsProperty('email', email)) + ..add(DiagnosticsProperty('phone', phone)) + ..add(DiagnosticsProperty('address', address)) + ..add(DiagnosticsProperty('isDefault', isDefault)) + ..add(DiagnosticsProperty('isActive', isActive)) + ..add(DiagnosticsProperty('metadata', metadata)) + ..add(DiagnosticsProperty('createdAt', createdAt)) + ..add(DiagnosticsProperty('updatedAt', updatedAt)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CustomerDtoImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.organizationId, organizationId) || + other.organizationId == organizationId) && + (identical(other.name, name) || other.name == name) && + (identical(other.email, email) || other.email == email) && + (identical(other.phone, phone) || other.phone == phone) && + (identical(other.address, address) || other.address == address) && + (identical(other.isDefault, isDefault) || + other.isDefault == isDefault) && + (identical(other.isActive, isActive) || + other.isActive == isActive) && + const DeepCollectionEquality().equals(other._metadata, _metadata) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + id, + organizationId, + name, + email, + phone, + address, + isDefault, + isActive, + const DeepCollectionEquality().hash(_metadata), + createdAt, + updatedAt, + ); + + /// Create a copy of CustomerDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CustomerDtoImplCopyWith<_$CustomerDtoImpl> get copyWith => + __$$CustomerDtoImplCopyWithImpl<_$CustomerDtoImpl>(this, _$identity); + + @override + Map toJson() { + return _$$CustomerDtoImplToJson(this); + } +} + +abstract class _CustomerDto extends CustomerDto { + const factory _CustomerDto({ + @JsonKey(name: "id") final String? id, + @JsonKey(name: "organization_id") final String? organizationId, + @JsonKey(name: "name") final String? name, + @JsonKey(name: "email") final String? email, + @JsonKey(name: "phone") final String? phone, + @JsonKey(name: "address") final String? address, + @JsonKey(name: "is_default") final bool? isDefault, + @JsonKey(name: "is_active") final bool? isActive, + @JsonKey(name: "metadata") final Map? metadata, + @JsonKey(name: "created_at") final String? createdAt, + @JsonKey(name: "updated_at") final String? updatedAt, + }) = _$CustomerDtoImpl; + const _CustomerDto._() : super._(); + + factory _CustomerDto.fromJson(Map json) = + _$CustomerDtoImpl.fromJson; + + @override + @JsonKey(name: "id") + String? get id; + @override + @JsonKey(name: "organization_id") + String? get organizationId; + @override + @JsonKey(name: "name") + String? get name; + @override + @JsonKey(name: "email") + String? get email; + @override + @JsonKey(name: "phone") + String? get phone; + @override + @JsonKey(name: "address") + String? get address; + @override + @JsonKey(name: "is_default") + bool? get isDefault; + @override + @JsonKey(name: "is_active") + bool? get isActive; + @override + @JsonKey(name: "metadata") + Map? get metadata; + @override + @JsonKey(name: "created_at") + String? get createdAt; + @override + @JsonKey(name: "updated_at") + String? get updatedAt; + + /// Create a copy of CustomerDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CustomerDtoImplCopyWith<_$CustomerDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/infrastructure/customer/customer_dtos.g.dart b/lib/infrastructure/customer/customer_dtos.g.dart new file mode 100644 index 0000000..c04080e --- /dev/null +++ b/lib/infrastructure/customer/customer_dtos.g.dart @@ -0,0 +1,59 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'customer_dtos.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ListCustomerDtoImpl _$$ListCustomerDtoImplFromJson( + Map json, +) => _$ListCustomerDtoImpl( + customers: (json['data'] as List?) + ?.map((e) => CustomerDto.fromJson(e as Map)) + .toList(), + totalCount: (json['total_count'] as num?)?.toInt(), + page: (json['page'] as num?)?.toInt(), + limit: (json['limit'] as num?)?.toInt(), + totalPages: (json['total_pages'] as num?)?.toInt(), +); + +Map _$$ListCustomerDtoImplToJson( + _$ListCustomerDtoImpl instance, +) => { + 'data': instance.customers, + 'total_count': instance.totalCount, + 'page': instance.page, + 'limit': instance.limit, + 'total_pages': instance.totalPages, +}; + +_$CustomerDtoImpl _$$CustomerDtoImplFromJson(Map json) => + _$CustomerDtoImpl( + id: json['id'] as String?, + organizationId: json['organization_id'] as String?, + name: json['name'] as String?, + email: json['email'] as String?, + phone: json['phone'] as String?, + address: json['address'] as String?, + isDefault: json['is_default'] as bool?, + isActive: json['is_active'] as bool?, + metadata: json['metadata'] as Map?, + createdAt: json['created_at'] as String?, + updatedAt: json['updated_at'] as String?, + ); + +Map _$$CustomerDtoImplToJson(_$CustomerDtoImpl instance) => + { + 'id': instance.id, + 'organization_id': instance.organizationId, + 'name': instance.name, + 'email': instance.email, + 'phone': instance.phone, + 'address': instance.address, + 'is_default': instance.isDefault, + 'is_active': instance.isActive, + 'metadata': instance.metadata, + 'created_at': instance.createdAt, + 'updated_at': instance.updatedAt, + }; diff --git a/lib/infrastructure/customer/datasources/remote_data_provider.dart b/lib/infrastructure/customer/datasources/remote_data_provider.dart new file mode 100644 index 0000000..4ec2810 --- /dev/null +++ b/lib/infrastructure/customer/datasources/remote_data_provider.dart @@ -0,0 +1,45 @@ +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/customer/customer.dart'; +import '../customer_dtos.dart'; + +@injectable +class CustomerRemoteDataProvider { + final ApiClient _apiClient; + final _logName = 'CustomerRemoteDataProvider'; + + CustomerRemoteDataProvider(this._apiClient); + + Future> fetchCustomers({ + int page = 1, + int limit = 10, + }) async { + try { + final response = await _apiClient.get( + ApiPath.customers, + params: {'page': page, 'limit': limit}, + headers: getAuthorizationHeader(), + ); + + if (response.data['success'] == false) { + return DC.error(CustomerFailure.unexpectedError()); + } + + final customers = ListCustomerDto.fromJson( + response.data['data'] as Map, + ); + + return DC.data(customers); + } on ApiFailure catch (e, s) { + log('fetchCustomersError', name: _logName, error: e, stackTrace: s); + return DC.error(CustomerFailure.serverError(e)); + } + } +} diff --git a/lib/infrastructure/customer/dtos/customer_dto.dart b/lib/infrastructure/customer/dtos/customer_dto.dart new file mode 100644 index 0000000..7db760a --- /dev/null +++ b/lib/infrastructure/customer/dtos/customer_dto.dart @@ -0,0 +1,62 @@ +part of '../customer_dtos.dart'; + +@freezed +class ListCustomerDto with _$ListCustomerDto { + const ListCustomerDto._(); + + const factory ListCustomerDto({ + @JsonKey(name: "data") List? customers, + @JsonKey(name: "total_count") int? totalCount, + @JsonKey(name: "page") int? page, + @JsonKey(name: "limit") int? limit, + @JsonKey(name: "total_pages") int? totalPages, + }) = _ListCustomerDto; + + factory ListCustomerDto.fromJson(Map json) => + _$ListCustomerDtoFromJson(json); + + ListCustomer toDomain() => ListCustomer( + customers: customers?.map((e) => e.toDomain()).toList() ?? [], + totalCount: totalCount ?? 0, + page: page ?? 0, + limit: limit ?? 0, + totalPages: totalPages ?? 0, + ); +} + +@freezed +class CustomerDto with _$CustomerDto { + const CustomerDto._(); + + const factory CustomerDto({ + @JsonKey(name: "id") String? id, + @JsonKey(name: "organization_id") String? organizationId, + @JsonKey(name: "name") String? name, + @JsonKey(name: "email") String? email, + @JsonKey(name: "phone") String? phone, + @JsonKey(name: "address") String? address, + @JsonKey(name: "is_default") bool? isDefault, + @JsonKey(name: "is_active") bool? isActive, + @JsonKey(name: "metadata") Map? metadata, + @JsonKey(name: "created_at") String? createdAt, + @JsonKey(name: "updated_at") String? updatedAt, + }) = _CustomerDto; + + factory CustomerDto.fromJson(Map json) => + _$CustomerDtoFromJson(json); + + /// Mapping ke domain + Customer toDomain() => Customer( + id: id ?? '', + organizationId: organizationId ?? '', + name: name ?? '', + email: email ?? '', + phone: phone ?? '', + address: address ?? '', + isDefault: isDefault ?? false, + isActive: isActive ?? false, + metadata: metadata ?? {}, + createdAt: createdAt != null ? DateTime.parse(createdAt!) : DateTime(1970), + updatedAt: updatedAt != null ? DateTime.parse(updatedAt!) : DateTime(1970), + ); +} diff --git a/lib/infrastructure/customer/repositories/customer_repository.dart b/lib/infrastructure/customer/repositories/customer_repository.dart new file mode 100644 index 0000000..68e74ae --- /dev/null +++ b/lib/infrastructure/customer/repositories/customer_repository.dart @@ -0,0 +1,38 @@ +import 'dart:developer'; + +import 'package:dartz/dartz.dart'; +import 'package:injectable/injectable.dart'; + +import '../../../domain/customer/customer.dart'; +import '../datasources/remote_data_provider.dart'; + +@Injectable(as: ICustomerRepository) +class CustomerRepository implements ICustomerRepository { + final CustomerRemoteDataProvider _remoteDataProvider; + final _logName = 'CustomerRepository'; + + CustomerRepository(this._remoteDataProvider); + + @override + Future> getCustomer({ + int page = 1, + int limit = 10, + }) async { + try { + final result = await _remoteDataProvider.fetchCustomers( + page: page, + limit: limit, + ); + + if (result.hasError) { + return left(result.error!); + } + + final customers = result.data!.toDomain(); + return right(customers); + } catch (e) { + log('getCustomerError', name: _logName, error: e); + return left(const CustomerFailure.unexpectedError()); + } + } +} diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 8459d75..a78a27a 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -16,6 +16,8 @@ import 'package:apskel_pos_flutter_v2/application/category/category_loader/categ as _i1018; import 'package:apskel_pos_flutter_v2/application/checkout/checkout_form/checkout_form_bloc.dart' as _i13; +import 'package:apskel_pos_flutter_v2/application/customer/customer_loader/customer_loader_bloc.dart' + as _i683; import 'package:apskel_pos_flutter_v2/application/outlet/outlet_loader/outlet_loader_bloc.dart' as _i76; import 'package:apskel_pos_flutter_v2/application/product/product_loader/product_loader_bloc.dart' @@ -38,6 +40,7 @@ import 'package:apskel_pos_flutter_v2/common/network/network_client.dart' as _i171; import 'package:apskel_pos_flutter_v2/domain/auth/auth.dart' as _i776; import 'package:apskel_pos_flutter_v2/domain/category/category.dart' as _i502; +import 'package:apskel_pos_flutter_v2/domain/customer/customer.dart' as _i143; import 'package:apskel_pos_flutter_v2/domain/outlet/outlet.dart' as _i552; import 'package:apskel_pos_flutter_v2/domain/product/product.dart' as _i44; import 'package:apskel_pos_flutter_v2/domain/table/table.dart' as _i983; @@ -54,6 +57,10 @@ import 'package:apskel_pos_flutter_v2/infrastructure/category/datasources/remote as _i856; import 'package:apskel_pos_flutter_v2/infrastructure/category/repositories/category_repository.dart' as _i604; +import 'package:apskel_pos_flutter_v2/infrastructure/customer/datasources/remote_data_provider.dart' + as _i841; +import 'package:apskel_pos_flutter_v2/infrastructure/customer/repositories/customer_repository.dart' + as _i385; import 'package:apskel_pos_flutter_v2/infrastructure/outlet/datasources/local_data_provider.dart' as _i693; import 'package:apskel_pos_flutter_v2/infrastructure/outlet/datasources/remote_data_provider.dart' @@ -137,6 +144,9 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i95.TableRemoteDataProvider>( () => _i95.TableRemoteDataProvider(gh<_i457.ApiClient>()), ); + gh.factory<_i841.CustomerRemoteDataProvider>( + () => _i841.CustomerRemoteDataProvider(gh<_i457.ApiClient>()), + ); gh.factory<_i776.IAuthRepository>( () => _i941.AuthRepository( gh<_i370.AuthRemoteDataProvider>(), @@ -179,6 +189,12 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i1018.CategoryLoaderBloc>( () => _i1018.CategoryLoaderBloc(gh<_i502.ICategoryRepository>()), ); + gh.factory<_i143.ICustomerRepository>( + () => _i385.CustomerRepository(gh<_i841.CustomerRemoteDataProvider>()), + ); + gh.factory<_i683.CustomerLoaderBloc>( + () => _i683.CustomerLoaderBloc(gh<_i143.ICustomerRepository>()), + ); gh.factory<_i343.AuthBloc>( () => _i343.AuthBloc( gh<_i776.IAuthRepository>(), diff --git a/lib/presentation/components/border/dashed_border.dart b/lib/presentation/components/border/dashed_border.dart new file mode 100644 index 0000000..5e612f7 --- /dev/null +++ b/lib/presentation/components/border/dashed_border.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +class DashedDivider extends StatelessWidget { + final double height; + final double dashWidth; + final double dashSpacing; + final Color color; + + const DashedDivider({ + super.key, + this.height = 1, + this.dashWidth = 5, + this.dashSpacing = 3, + this.color = Colors.grey, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: height, + child: LayoutBuilder( + builder: (context, constraints) { + final boxWidth = constraints.constrainWidth(); + final dashCount = (boxWidth / (dashWidth + dashSpacing)).floor(); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate(dashCount, (_) { + return SizedBox( + width: dashWidth, + height: height, + child: DecoratedBox(decoration: BoxDecoration(color: color)), + ); + }), + ); + }, + ), + ); + } +} diff --git a/lib/presentation/components/card/customer_card.dart b/lib/presentation/components/card/customer_card.dart new file mode 100644 index 0000000..ba14fd1 --- /dev/null +++ b/lib/presentation/components/card/customer_card.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; + +import '../../../common/theme/theme.dart'; +import '../../../domain/customer/customer.dart'; + +class CustomerCard extends StatelessWidget { + final Customer customer; + final bool isActive; + final Function() onTap; + const CustomerCard({ + super.key, + required this.customer, + required this.isActive, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 16).copyWith(bottom: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isActive ? AppColor.primary.withOpacity(0.1) : AppColor.white, + border: Border.all( + color: isActive ? AppColor.primary : AppColor.border, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 22, + backgroundColor: AppColor.primary, + child: Icon(Icons.person, color: Colors.white), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + customer.name, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + Text( + customer.email.isNotEmpty ? customer.email : '-', + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/components/page/page_title.dart b/lib/presentation/components/page/page_title.dart new file mode 100644 index 0000000..66aa092 --- /dev/null +++ b/lib/presentation/components/page/page_title.dart @@ -0,0 +1,63 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +import '../../../common/extension/extension.dart'; +import '../../../common/theme/theme.dart'; +import '../spaces/space.dart'; + +class PageTitle extends StatelessWidget { + final String title; + final String? subtitle; + final bool isBack; + final List? actionWidget; + const PageTitle({ + super.key, + required this.title, + this.subtitle, + this.isBack = true, + this.actionWidget, + }); + + @override + Widget build(BuildContext context) { + return Container( + height: context.deviceHeight * 0.123, + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), + decoration: BoxDecoration( + color: AppColor.white, + border: Border(bottom: BorderSide(color: AppColor.border, width: 1.0)), + ), + child: Row( + children: [ + if (isBack) ...[ + GestureDetector( + onTap: () => context.maybePop(), + child: Icon(Icons.arrow_back, color: AppColor.primary, size: 24), + ), + SpaceWidth(16), + ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: AppStyle.xxl.copyWith(fontWeight: FontWeight.w600), + ), + if (subtitle != null) ...[ + const SizedBox(height: 4.0), + Text( + subtitle!, + style: AppStyle.md.copyWith(color: AppColor.textSecondary), + ), + ], + ], + ), + ), + if (actionWidget != null) ...actionWidget!, + ], + ), + ); + } +} diff --git a/lib/presentation/pages/main/pages/customer/customer_page.dart b/lib/presentation/pages/main/pages/customer/customer_page.dart index a93f8ee..d765984 100644 --- a/lib/presentation/pages/main/pages/customer/customer_page.dart +++ b/lib/presentation/pages/main/pages/customer/customer_page.dart @@ -1,12 +1,269 @@ +import 'package:apskel_pos_flutter_v2/domain/customer/customer.dart'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../../../../application/customer/customer_loader/customer_loader_bloc.dart'; +import '../../../../../common/extension/extension.dart'; +import '../../../../../common/theme/theme.dart'; +import '../../../../../injection.dart'; +import '../../../../components/border/dashed_border.dart'; +import '../../../../components/card/customer_card.dart'; +import '../../../../components/card/error_card.dart'; +import '../../../../components/loader/loader_with_text.dart'; +import '../../../../components/page/page_title.dart'; +import '../../../../components/spaces/space.dart'; @RoutePage() -class CustomerPage extends StatelessWidget { +class CustomerPage extends StatelessWidget implements AutoRouteWrapper { const CustomerPage({super.key}); @override Widget build(BuildContext context) { - return const Placeholder(); + return Scaffold( + backgroundColor: AppColor.background, + body: BlocBuilder( + builder: (context, state) { + return Row( + children: [ + Expanded( + flex: 2, + child: Material( + color: AppColor.white, + child: Column( + children: [ + PageTitle(title: 'Daftar Pelanggan'), + Expanded( + child: state.isFetching + ? Center(child: const LoaderWithText()) + : state.failureOrOption.fold( + () => ListView.builder( + itemCount: state.customers.length, + itemBuilder: (context, index) { + final customer = state.customers[index]; + return CustomerCard( + customer: customer, + isActive: + customer == state.selectedCustomer, + onTap: () { + context.read().add( + CustomerLoaderEvent.setSelectedCustomer( + customer, + ), + ); + }, + ); + }, + ), + (f) => _buildErrorState(f, context), + ), + ), + ], + ), + ), + ), + Expanded( + flex: 4, + child: state.selectedCustomer == null + ? Center( + child: Text( + "Belum ada pelanggan yang dipilih.", + style: AppStyle.lg.copyWith( + fontSize: 16.0, + fontWeight: FontWeight.w600, + ), + ), + ) + : Center( + child: Container( + width: context.deviceHeight * 0.5, + height: context.deviceHeight * 0.6, + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 16.0, + ), + child: Column( + children: [ + CircleAvatar( + radius: 24, + backgroundColor: AppColor.primary, + child: Icon( + Icons.person, + color: Colors.white, + ), + ), + const SizedBox(height: 12), + Text( + state.selectedCustomer?.name ?? "", + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + DashedDivider(color: AppColor.border), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 16.0, + ), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'No. Handphone', + style: TextStyle(fontSize: 12.0), + ), + Text( + (state + .selectedCustomer + ?.phone + .isEmpty ?? + true) + ? "-" + : state.selectedCustomer?.phone ?? + "-", + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SpaceHeight(8), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Email', + style: TextStyle(fontSize: 12.0), + ), + Text( + (state + .selectedCustomer + ?.email + .isEmpty ?? + true) + ? "-" + : state.selectedCustomer?.email ?? + "-", + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SpaceHeight(8), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Alamat', + style: TextStyle(fontSize: 12.0), + ), + Text( + (state + .selectedCustomer + ?.address + .isEmpty ?? + true) + ? "-" + : state + .selectedCustomer + ?.address ?? + "-", + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + ), + ], + ); + }, + ), + ); } + + Widget _buildErrorState(CustomerFailure f, BuildContext context) { + return f.maybeMap( + orElse: () => ErrorCard( + title: "Pelanggan", + message: "Terjadi kesalahan saat memuat pelanggan", + onTap: () { + context.read().add( + CustomerLoaderEvent.fetched(isRefresh: true), + ); + }, + ), + empty: (value) => ErrorCard( + title: "Pelanggan", + message: "Pelanggan masih kosong, silahkan tambahkan pelanggan", + onTap: () { + context.read().add( + CustomerLoaderEvent.fetched(isRefresh: true), + ); + }, + ), + serverError: (value) => ErrorCard( + title: "Pelanggan", + message: "Terjadi kesalahan saat memuat pelanggan", + onTap: () { + context.read().add( + CustomerLoaderEvent.fetched(isRefresh: true), + ); + }, + ), + dynamicErrorMessage: (value) => ErrorCard( + title: "Pelanggan", + message: value.erroMessage, + onTap: () { + context.read().add( + CustomerLoaderEvent.fetched(isRefresh: true), + ); + }, + ), + unexpectedError: (value) => ErrorCard( + title: "Pelanggan", + message: "Terjadi kesalahan saat memuat pelanggan", + onTap: () { + context.read().add( + CustomerLoaderEvent.fetched(isRefresh: true), + ); + }, + ), + ); + } + + @override + Widget wrappedRoute(BuildContext context) => BlocProvider( + create: (context) => + getIt() + ..add(CustomerLoaderEvent.fetched(isRefresh: true)), + child: this, + ); } diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index 025390b..4be9313 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -40,7 +40,7 @@ class CustomerRoute extends _i10.PageRouteInfo { static _i10.PageInfo page = _i10.PageInfo( name, builder: (data) { - return const _i1.CustomerPage(); + return _i10.WrappedRoute(child: const _i1.CustomerPage()); }, ); }