Compare commits

..
17 Commits
Author SHA1 Message Date
Efril 7887704a5c update service type 2026-01-16 16:07:56 +07:00
Efril 4c12244d3c checkout page 2026-01-16 15:53:06 +07:00
Efril f4f775b9ed menu detail page 2026-01-16 14:41:09 +07:00
Efril 44d48d41d4 menu page 2026-01-16 13:27:09 +07:00
efrilm 82e1f93cce update 2026-01-16 12:26:06 +07:00
efrilm 1ce980a87b mystery box 2025-10-12 13:27:39 +07:00
efrilm 909c312af0 Ferish Wheel and Music 2025-09-18 14:53:39 +07:00
efrilm 73918430b2 Customer Point 2025-09-18 13:01:31 +07:00
efrilm a5d66c63b7 State Is Authenticated 2025-09-18 12:25:48 +07:00
efrilm 3c596461c6 Game Prize and Logout 2025-09-18 10:39:54 +07:00
efrilm 006486bc2a Auth 2025-09-18 09:31:42 +07:00
efrilm 2e00207343 Set Password 2025-09-18 09:17:25 +07:00
efrilm 8e35582f93 Otp Page 2025-09-18 09:03:50 +07:00
efrilm 0ea1a6fa56 Register Impl 2025-09-18 08:48:36 +07:00
efrilm cee78e179b login impl 2025-09-18 08:17:24 +07:00
efrilm 1ca1a45126 check phone impl 2025-09-18 08:01:49 +07:00
efrilm 214dfe3262 Update 2025-09-18 07:28:01 +07:00
134 changed files with 11807 additions and 1925 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

+49
View File
@@ -0,0 +1,49 @@
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../domain/auth/auth.dart';
part 'auth_event.dart';
part 'auth_state.dart';
part 'auth_bloc.freezed.dart';
@injectable
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final IAuthRepository _repository;
AuthBloc(this._repository) : super(AuthState.initial()) {
on<AuthEvent>(_onAuthEvent);
}
Future<void> _onAuthEvent(AuthEvent event, Emitter<AuthState> emit) {
return event.map(
fetchCurrentUser: (e) async {
emit(state.copyWith(failureOption: none()));
final token = await _repository.hasToken();
final failureOrAuth = await _repository.currentUser();
failureOrAuth.fold(
(f) => emit(
state.copyWith(
failureOption: optionOf(f),
status: token
? AuthStatus.authenticated()
: AuthStatus.unauthenticated(),
),
),
(user) => emit(
state.copyWith(
user: user,
status: token
? AuthStatus.authenticated()
: AuthStatus.unauthenticated(),
),
),
);
},
);
}
}
+806
View File
@@ -0,0 +1,806 @@
// 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 'auth_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$AuthEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetchCurrentUser,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetchCurrentUser,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetchCurrentUser,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_FetchCurrentUser value) fetchCurrentUser,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_FetchCurrentUser value)? fetchCurrentUser,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_FetchCurrentUser value)? fetchCurrentUser,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AuthEventCopyWith<$Res> {
factory $AuthEventCopyWith(AuthEvent value, $Res Function(AuthEvent) then) =
_$AuthEventCopyWithImpl<$Res, AuthEvent>;
}
/// @nodoc
class _$AuthEventCopyWithImpl<$Res, $Val extends AuthEvent>
implements $AuthEventCopyWith<$Res> {
_$AuthEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of AuthEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FetchCurrentUserImplCopyWith<$Res> {
factory _$$FetchCurrentUserImplCopyWith(
_$FetchCurrentUserImpl value,
$Res Function(_$FetchCurrentUserImpl) then,
) = __$$FetchCurrentUserImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchCurrentUserImplCopyWithImpl<$Res>
extends _$AuthEventCopyWithImpl<$Res, _$FetchCurrentUserImpl>
implements _$$FetchCurrentUserImplCopyWith<$Res> {
__$$FetchCurrentUserImplCopyWithImpl(
_$FetchCurrentUserImpl _value,
$Res Function(_$FetchCurrentUserImpl) _then,
) : super(_value, _then);
/// Create a copy of AuthEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchCurrentUserImpl implements _FetchCurrentUser {
const _$FetchCurrentUserImpl();
@override
String toString() {
return 'AuthEvent.fetchCurrentUser()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchCurrentUserImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetchCurrentUser,
}) {
return fetchCurrentUser();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetchCurrentUser,
}) {
return fetchCurrentUser?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetchCurrentUser,
required TResult orElse(),
}) {
if (fetchCurrentUser != null) {
return fetchCurrentUser();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_FetchCurrentUser value) fetchCurrentUser,
}) {
return fetchCurrentUser(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_FetchCurrentUser value)? fetchCurrentUser,
}) {
return fetchCurrentUser?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_FetchCurrentUser value)? fetchCurrentUser,
required TResult orElse(),
}) {
if (fetchCurrentUser != null) {
return fetchCurrentUser(this);
}
return orElse();
}
}
abstract class _FetchCurrentUser implements AuthEvent {
const factory _FetchCurrentUser() = _$FetchCurrentUserImpl;
}
/// @nodoc
mixin _$AuthState {
User get user => throw _privateConstructorUsedError;
AuthStatus get status => throw _privateConstructorUsedError;
Option<AuthFailure> get failureOption => throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$AuthStateCopyWith<AuthState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AuthStateCopyWith<$Res> {
factory $AuthStateCopyWith(AuthState value, $Res Function(AuthState) then) =
_$AuthStateCopyWithImpl<$Res, AuthState>;
@useResult
$Res call({
User user,
AuthStatus status,
Option<AuthFailure> failureOption,
bool isFetching,
});
$UserCopyWith<$Res> get user;
$AuthStatusCopyWith<$Res> get status;
}
/// @nodoc
class _$AuthStateCopyWithImpl<$Res, $Val extends AuthState>
implements $AuthStateCopyWith<$Res> {
_$AuthStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? user = null,
Object? status = null,
Object? failureOption = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
user: null == user
? _value.user
: user // ignore: cast_nullable_to_non_nullable
as User,
status: null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as AuthStatus,
failureOption: null == failureOption
? _value.failureOption
: failureOption // ignore: cast_nullable_to_non_nullable
as Option<AuthFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$UserCopyWith<$Res> get user {
return $UserCopyWith<$Res>(_value.user, (value) {
return _then(_value.copyWith(user: value) as $Val);
});
}
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AuthStatusCopyWith<$Res> get status {
return $AuthStatusCopyWith<$Res>(_value.status, (value) {
return _then(_value.copyWith(status: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$AuthStateImplCopyWith<$Res>
implements $AuthStateCopyWith<$Res> {
factory _$$AuthStateImplCopyWith(
_$AuthStateImpl value,
$Res Function(_$AuthStateImpl) then,
) = __$$AuthStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
User user,
AuthStatus status,
Option<AuthFailure> failureOption,
bool isFetching,
});
@override
$UserCopyWith<$Res> get user;
@override
$AuthStatusCopyWith<$Res> get status;
}
/// @nodoc
class __$$AuthStateImplCopyWithImpl<$Res>
extends _$AuthStateCopyWithImpl<$Res, _$AuthStateImpl>
implements _$$AuthStateImplCopyWith<$Res> {
__$$AuthStateImplCopyWithImpl(
_$AuthStateImpl _value,
$Res Function(_$AuthStateImpl) _then,
) : super(_value, _then);
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? user = null,
Object? status = null,
Object? failureOption = null,
Object? isFetching = null,
}) {
return _then(
_$AuthStateImpl(
user: null == user
? _value.user
: user // ignore: cast_nullable_to_non_nullable
as User,
status: null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as AuthStatus,
failureOption: null == failureOption
? _value.failureOption
: failureOption // ignore: cast_nullable_to_non_nullable
as Option<AuthFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$AuthStateImpl extends _AuthState {
const _$AuthStateImpl({
required this.user,
this.status = const AuthStatus.initial(),
required this.failureOption,
this.isFetching = false,
}) : super._();
@override
final User user;
@override
@JsonKey()
final AuthStatus status;
@override
final Option<AuthFailure> failureOption;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'AuthState(user: $user, status: $status, failureOption: $failureOption, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$AuthStateImpl &&
(identical(other.user, user) || other.user == user) &&
(identical(other.status, status) || other.status == status) &&
(identical(other.failureOption, failureOption) ||
other.failureOption == failureOption) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode =>
Object.hash(runtimeType, user, status, failureOption, isFetching);
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$AuthStateImplCopyWith<_$AuthStateImpl> get copyWith =>
__$$AuthStateImplCopyWithImpl<_$AuthStateImpl>(this, _$identity);
}
abstract class _AuthState extends AuthState {
const factory _AuthState({
required final User user,
final AuthStatus status,
required final Option<AuthFailure> failureOption,
final bool isFetching,
}) = _$AuthStateImpl;
const _AuthState._() : super._();
@override
User get user;
@override
AuthStatus get status;
@override
Option<AuthFailure> get failureOption;
@override
bool get isFetching;
/// Create a copy of AuthState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$AuthStateImplCopyWith<_$AuthStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$AuthStatus {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function() initial,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? authenticated,
TResult? Function()? unauthenticated,
TResult? Function()? initial,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Authenticated value) authenticated,
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Authenticated value)? authenticated,
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_Initial value)? initial,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Authenticated value)? authenticated,
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AuthStatusCopyWith<$Res> {
factory $AuthStatusCopyWith(
AuthStatus value,
$Res Function(AuthStatus) then,
) = _$AuthStatusCopyWithImpl<$Res, AuthStatus>;
}
/// @nodoc
class _$AuthStatusCopyWithImpl<$Res, $Val extends AuthStatus>
implements $AuthStatusCopyWith<$Res> {
_$AuthStatusCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of AuthStatus
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$AuthenticatedImplCopyWith<$Res> {
factory _$$AuthenticatedImplCopyWith(
_$AuthenticatedImpl value,
$Res Function(_$AuthenticatedImpl) then,
) = __$$AuthenticatedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$AuthenticatedImplCopyWithImpl<$Res>
extends _$AuthStatusCopyWithImpl<$Res, _$AuthenticatedImpl>
implements _$$AuthenticatedImplCopyWith<$Res> {
__$$AuthenticatedImplCopyWithImpl(
_$AuthenticatedImpl _value,
$Res Function(_$AuthenticatedImpl) _then,
) : super(_value, _then);
/// Create a copy of AuthStatus
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$AuthenticatedImpl implements _Authenticated {
const _$AuthenticatedImpl();
@override
String toString() {
return 'AuthStatus.authenticated()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$AuthenticatedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function() initial,
}) {
return authenticated();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? authenticated,
TResult? Function()? unauthenticated,
TResult? Function()? initial,
}) {
return authenticated?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) {
if (authenticated != null) {
return authenticated();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Authenticated value) authenticated,
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) {
return authenticated(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Authenticated value)? authenticated,
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_Initial value)? initial,
}) {
return authenticated?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Authenticated value)? authenticated,
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) {
if (authenticated != null) {
return authenticated(this);
}
return orElse();
}
}
abstract class _Authenticated implements AuthStatus {
const factory _Authenticated() = _$AuthenticatedImpl;
}
/// @nodoc
abstract class _$$UnauthenticatedImplCopyWith<$Res> {
factory _$$UnauthenticatedImplCopyWith(
_$UnauthenticatedImpl value,
$Res Function(_$UnauthenticatedImpl) then,
) = __$$UnauthenticatedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$UnauthenticatedImplCopyWithImpl<$Res>
extends _$AuthStatusCopyWithImpl<$Res, _$UnauthenticatedImpl>
implements _$$UnauthenticatedImplCopyWith<$Res> {
__$$UnauthenticatedImplCopyWithImpl(
_$UnauthenticatedImpl _value,
$Res Function(_$UnauthenticatedImpl) _then,
) : super(_value, _then);
/// Create a copy of AuthStatus
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$UnauthenticatedImpl implements _Unauthenticated {
const _$UnauthenticatedImpl();
@override
String toString() {
return 'AuthStatus.unauthenticated()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$UnauthenticatedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function() initial,
}) {
return unauthenticated();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? authenticated,
TResult? Function()? unauthenticated,
TResult? Function()? initial,
}) {
return unauthenticated?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) {
if (unauthenticated != null) {
return unauthenticated();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Authenticated value) authenticated,
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) {
return unauthenticated(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Authenticated value)? authenticated,
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_Initial value)? initial,
}) {
return unauthenticated?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Authenticated value)? authenticated,
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) {
if (unauthenticated != null) {
return unauthenticated(this);
}
return orElse();
}
}
abstract class _Unauthenticated implements AuthStatus {
const factory _Unauthenticated() = _$UnauthenticatedImpl;
}
/// @nodoc
abstract class _$$InitialImplCopyWith<$Res> {
factory _$$InitialImplCopyWith(
_$InitialImpl value,
$Res Function(_$InitialImpl) then,
) = __$$InitialImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$InitialImplCopyWithImpl<$Res>
extends _$AuthStatusCopyWithImpl<$Res, _$InitialImpl>
implements _$$InitialImplCopyWith<$Res> {
__$$InitialImplCopyWithImpl(
_$InitialImpl _value,
$Res Function(_$InitialImpl) _then,
) : super(_value, _then);
/// Create a copy of AuthStatus
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$InitialImpl implements _Initial {
const _$InitialImpl();
@override
String toString() {
return 'AuthStatus.initial()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$InitialImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function() initial,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? authenticated,
TResult? Function()? unauthenticated,
TResult? Function()? initial,
}) {
return initial?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Authenticated value) authenticated,
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Authenticated value)? authenticated,
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_Initial value)? initial,
}) {
return initial?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Authenticated value)? authenticated,
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements AuthStatus {
const factory _Initial() = _$InitialImpl;
}
+6
View File
@@ -0,0 +1,6 @@
part of 'auth_bloc.dart';
@freezed
class AuthEvent with _$AuthEvent {
const factory AuthEvent.fetchCurrentUser() = _FetchCurrentUser;
}
+26
View File
@@ -0,0 +1,26 @@
part of 'auth_bloc.dart';
@freezed
class AuthState with _$AuthState {
const AuthState._();
const factory AuthState({
required User user,
@Default(AuthStatus.initial()) AuthStatus status,
required Option<AuthFailure> failureOption,
@Default(false) bool isFetching,
}) = _AuthState;
factory AuthState.initial() =>
AuthState(user: User.empty(), failureOption: none());
bool get isAuthenticated => status == const AuthStatus.authenticated();
bool get isInitial => status == const AuthStatus.initial();
}
@freezed
sealed class AuthStatus with _$AuthStatus {
const factory AuthStatus.authenticated() = _Authenticated;
const factory AuthStatus.unauthenticated() = _Unauthenticated;
const factory AuthStatus.initial() = _Initial;
}
@@ -3,6 +3,7 @@ import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import '../../../common/function/app_function.dart';
import '../../../domain/auth/auth.dart'; import '../../../domain/auth/auth.dart';
part 'check_phone_form_event.dart'; part 'check_phone_form_event.dart';
@@ -40,7 +41,7 @@ class CheckPhoneFormBloc
if (phoneNumberValid) { if (phoneNumberValid) {
failureOrCheckPhone = await _repository.checkPhone( failureOrCheckPhone = await _repository.checkPhone(
phoneNumber: state.phoneNumber, phoneNumber: getNormalizePhone(state.phoneNumber),
); );
emit( emit(
state.copyWith( state.copyWith(
@@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
@@ -41,6 +43,10 @@ class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
final phoneNumberValid = state.phoneNumber.isNotEmpty; final phoneNumberValid = state.phoneNumber.isNotEmpty;
final passwordValid = state.password.isNotEmpty; final passwordValid = state.password.isNotEmpty;
log(
'phoneNumberValid: $phoneNumberValid, passwordValid: $passwordValid, phoneNumber: ${state.phoneNumber}, password: ${state.password}',
);
if (phoneNumberValid && passwordValid) { if (phoneNumberValid && passwordValid) {
failureOrLogin = await _authRepository.login( failureOrLogin = await _authRepository.login(
phoneNumber: state.phoneNumber, phoneNumber: state.phoneNumber,
@@ -0,0 +1,37 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/auth/auth.dart';
part 'logout_form_event.dart';
part 'logout_form_state.dart';
part 'logout_form_bloc.freezed.dart';
@injectable
class LogoutFormBloc extends Bloc<LogoutFormEvent, LogoutFormState> {
final IAuthRepository _repository;
LogoutFormBloc(this._repository) : super(LogoutFormState.initial()) {
on<LogoutFormEvent>(_onLogoutFormEvent);
}
Future<void> _onLogoutFormEvent(
LogoutFormEvent event,
Emitter<LogoutFormState> emit,
) {
return event.map(
submitted: (e) async {
emit(state.copyWith(isSubmitting: true, failureOrAuthOption: none()));
final failureOrAuth = await _repository.logout();
emit(
state.copyWith(
isSubmitting: false,
failureOrAuthOption: optionOf(failureOrAuth),
),
);
},
);
}
}
@@ -0,0 +1,335 @@
// 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 'logout_form_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$LogoutFormEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() submitted,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? submitted,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? submitted,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Submitted value) submitted,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Submitted value)? submitted,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Submitted value)? submitted,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $LogoutFormEventCopyWith<$Res> {
factory $LogoutFormEventCopyWith(
LogoutFormEvent value,
$Res Function(LogoutFormEvent) then,
) = _$LogoutFormEventCopyWithImpl<$Res, LogoutFormEvent>;
}
/// @nodoc
class _$LogoutFormEventCopyWithImpl<$Res, $Val extends LogoutFormEvent>
implements $LogoutFormEventCopyWith<$Res> {
_$LogoutFormEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of LogoutFormEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$SubmittedImplCopyWith<$Res> {
factory _$$SubmittedImplCopyWith(
_$SubmittedImpl value,
$Res Function(_$SubmittedImpl) then,
) = __$$SubmittedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$SubmittedImplCopyWithImpl<$Res>
extends _$LogoutFormEventCopyWithImpl<$Res, _$SubmittedImpl>
implements _$$SubmittedImplCopyWith<$Res> {
__$$SubmittedImplCopyWithImpl(
_$SubmittedImpl _value,
$Res Function(_$SubmittedImpl) _then,
) : super(_value, _then);
/// Create a copy of LogoutFormEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$SubmittedImpl implements _Submitted {
const _$SubmittedImpl();
@override
String toString() {
return 'LogoutFormEvent.submitted()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$SubmittedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() submitted,
}) {
return submitted();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? submitted,
}) {
return submitted?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? submitted,
required TResult orElse(),
}) {
if (submitted != null) {
return submitted();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Submitted value) submitted,
}) {
return submitted(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Submitted value)? submitted,
}) {
return submitted?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Submitted value)? submitted,
required TResult orElse(),
}) {
if (submitted != null) {
return submitted(this);
}
return orElse();
}
}
abstract class _Submitted implements LogoutFormEvent {
const factory _Submitted() = _$SubmittedImpl;
}
/// @nodoc
mixin _$LogoutFormState {
Option<Either<AuthFailure, Unit>> get failureOrAuthOption =>
throw _privateConstructorUsedError;
bool get isSubmitting => throw _privateConstructorUsedError;
/// Create a copy of LogoutFormState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$LogoutFormStateCopyWith<LogoutFormState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $LogoutFormStateCopyWith<$Res> {
factory $LogoutFormStateCopyWith(
LogoutFormState value,
$Res Function(LogoutFormState) then,
) = _$LogoutFormStateCopyWithImpl<$Res, LogoutFormState>;
@useResult
$Res call({
Option<Either<AuthFailure, Unit>> failureOrAuthOption,
bool isSubmitting,
});
}
/// @nodoc
class _$LogoutFormStateCopyWithImpl<$Res, $Val extends LogoutFormState>
implements $LogoutFormStateCopyWith<$Res> {
_$LogoutFormStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of LogoutFormState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? failureOrAuthOption = null, Object? isSubmitting = null}) {
return _then(
_value.copyWith(
failureOrAuthOption: null == failureOrAuthOption
? _value.failureOrAuthOption
: failureOrAuthOption // ignore: cast_nullable_to_non_nullable
as Option<Either<AuthFailure, Unit>>,
isSubmitting: null == isSubmitting
? _value.isSubmitting
: isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$LogoutFormStateImplCopyWith<$Res>
implements $LogoutFormStateCopyWith<$Res> {
factory _$$LogoutFormStateImplCopyWith(
_$LogoutFormStateImpl value,
$Res Function(_$LogoutFormStateImpl) then,
) = __$$LogoutFormStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
Option<Either<AuthFailure, Unit>> failureOrAuthOption,
bool isSubmitting,
});
}
/// @nodoc
class __$$LogoutFormStateImplCopyWithImpl<$Res>
extends _$LogoutFormStateCopyWithImpl<$Res, _$LogoutFormStateImpl>
implements _$$LogoutFormStateImplCopyWith<$Res> {
__$$LogoutFormStateImplCopyWithImpl(
_$LogoutFormStateImpl _value,
$Res Function(_$LogoutFormStateImpl) _then,
) : super(_value, _then);
/// Create a copy of LogoutFormState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? failureOrAuthOption = null, Object? isSubmitting = null}) {
return _then(
_$LogoutFormStateImpl(
failureOrAuthOption: null == failureOrAuthOption
? _value.failureOrAuthOption
: failureOrAuthOption // ignore: cast_nullable_to_non_nullable
as Option<Either<AuthFailure, Unit>>,
isSubmitting: null == isSubmitting
? _value.isSubmitting
: isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$LogoutFormStateImpl implements _LogoutFormState {
const _$LogoutFormStateImpl({
required this.failureOrAuthOption,
this.isSubmitting = false,
});
@override
final Option<Either<AuthFailure, Unit>> failureOrAuthOption;
@override
@JsonKey()
final bool isSubmitting;
@override
String toString() {
return 'LogoutFormState(failureOrAuthOption: $failureOrAuthOption, isSubmitting: $isSubmitting)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LogoutFormStateImpl &&
(identical(other.failureOrAuthOption, failureOrAuthOption) ||
other.failureOrAuthOption == failureOrAuthOption) &&
(identical(other.isSubmitting, isSubmitting) ||
other.isSubmitting == isSubmitting));
}
@override
int get hashCode =>
Object.hash(runtimeType, failureOrAuthOption, isSubmitting);
/// Create a copy of LogoutFormState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LogoutFormStateImplCopyWith<_$LogoutFormStateImpl> get copyWith =>
__$$LogoutFormStateImplCopyWithImpl<_$LogoutFormStateImpl>(
this,
_$identity,
);
}
abstract class _LogoutFormState implements LogoutFormState {
const factory _LogoutFormState({
required final Option<Either<AuthFailure, Unit>> failureOrAuthOption,
final bool isSubmitting,
}) = _$LogoutFormStateImpl;
@override
Option<Either<AuthFailure, Unit>> get failureOrAuthOption;
@override
bool get isSubmitting;
/// Create a copy of LogoutFormState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LogoutFormStateImplCopyWith<_$LogoutFormStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,6 @@
part of 'logout_form_bloc.dart';
@freezed
class LogoutFormEvent with _$LogoutFormEvent {
const factory LogoutFormEvent.submitted() = _Submitted;
}
@@ -0,0 +1,12 @@
part of 'logout_form_bloc.dart';
@freezed
class LogoutFormState with _$LogoutFormState {
const factory LogoutFormState({
required Option<Either<AuthFailure, Unit>> failureOrAuthOption,
@Default(false) bool isSubmitting,
}) = _LogoutFormState;
factory LogoutFormState.initial() =>
LogoutFormState(failureOrAuthOption: none(), isSubmitting: false);
}
@@ -0,0 +1,42 @@
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_point_loader_event.dart';
part 'customer_point_loader_state.dart';
part 'customer_point_loader_bloc.freezed.dart';
@injectable
class CustomerPointLoaderBloc
extends Bloc<CustomerPointLoaderEvent, CustomerPointLoaderState> {
final ICustomerRepository _repository;
CustomerPointLoaderBloc(this._repository)
: super(CustomerPointLoaderState.initial()) {
on<CustomerPointLoaderEvent>(_onCustomerPointLoaderEvent);
}
Future<void> _onCustomerPointLoaderEvent(
CustomerPointLoaderEvent event,
Emitter<CustomerPointLoaderState> emit,
) {
return event.map(
fetched: (e) async {
emit(
state.copyWith(isFetching: true, failureOptionCustomerPoint: none()),
);
final result = await _repository.getPoints();
var data = result.fold(
(f) => state.copyWith(failureOptionCustomerPoint: optionOf(f)),
(customerPoint) => state.copyWith(customerPoint: customerPoint),
);
emit(data.copyWith(isFetching: false));
},
);
}
}
@@ -0,0 +1,391 @@
// 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_point_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$CustomerPointLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CustomerPointLoaderEventCopyWith<$Res> {
factory $CustomerPointLoaderEventCopyWith(
CustomerPointLoaderEvent value,
$Res Function(CustomerPointLoaderEvent) then,
) = _$CustomerPointLoaderEventCopyWithImpl<$Res, CustomerPointLoaderEvent>;
}
/// @nodoc
class _$CustomerPointLoaderEventCopyWithImpl<
$Res,
$Val extends CustomerPointLoaderEvent
>
implements $CustomerPointLoaderEventCopyWith<$Res> {
_$CustomerPointLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CustomerPointLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$CustomerPointLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of CustomerPointLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl();
@override
String toString() {
return 'CustomerPointLoaderEvent.fetched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({required TResult Function() fetched}) {
return fetched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched}) {
return fetched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements CustomerPointLoaderEvent {
const factory _Fetched() = _$FetchedImpl;
}
/// @nodoc
mixin _$CustomerPointLoaderState {
CustomerPoint get customerPoint => throw _privateConstructorUsedError;
Option<CustomerFailure> get failureOptionCustomerPoint =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of CustomerPointLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CustomerPointLoaderStateCopyWith<CustomerPointLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CustomerPointLoaderStateCopyWith<$Res> {
factory $CustomerPointLoaderStateCopyWith(
CustomerPointLoaderState value,
$Res Function(CustomerPointLoaderState) then,
) = _$CustomerPointLoaderStateCopyWithImpl<$Res, CustomerPointLoaderState>;
@useResult
$Res call({
CustomerPoint customerPoint,
Option<CustomerFailure> failureOptionCustomerPoint,
bool isFetching,
});
$CustomerPointCopyWith<$Res> get customerPoint;
}
/// @nodoc
class _$CustomerPointLoaderStateCopyWithImpl<
$Res,
$Val extends CustomerPointLoaderState
>
implements $CustomerPointLoaderStateCopyWith<$Res> {
_$CustomerPointLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CustomerPointLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? customerPoint = null,
Object? failureOptionCustomerPoint = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
customerPoint: null == customerPoint
? _value.customerPoint
: customerPoint // ignore: cast_nullable_to_non_nullable
as CustomerPoint,
failureOptionCustomerPoint: null == failureOptionCustomerPoint
? _value.failureOptionCustomerPoint
: failureOptionCustomerPoint // ignore: cast_nullable_to_non_nullable
as Option<CustomerFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of CustomerPointLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CustomerPointCopyWith<$Res> get customerPoint {
return $CustomerPointCopyWith<$Res>(_value.customerPoint, (value) {
return _then(_value.copyWith(customerPoint: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$CustomerPointLoaderStateImplCopyWith<$Res>
implements $CustomerPointLoaderStateCopyWith<$Res> {
factory _$$CustomerPointLoaderStateImplCopyWith(
_$CustomerPointLoaderStateImpl value,
$Res Function(_$CustomerPointLoaderStateImpl) then,
) = __$$CustomerPointLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
CustomerPoint customerPoint,
Option<CustomerFailure> failureOptionCustomerPoint,
bool isFetching,
});
@override
$CustomerPointCopyWith<$Res> get customerPoint;
}
/// @nodoc
class __$$CustomerPointLoaderStateImplCopyWithImpl<$Res>
extends
_$CustomerPointLoaderStateCopyWithImpl<
$Res,
_$CustomerPointLoaderStateImpl
>
implements _$$CustomerPointLoaderStateImplCopyWith<$Res> {
__$$CustomerPointLoaderStateImplCopyWithImpl(
_$CustomerPointLoaderStateImpl _value,
$Res Function(_$CustomerPointLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of CustomerPointLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? customerPoint = null,
Object? failureOptionCustomerPoint = null,
Object? isFetching = null,
}) {
return _then(
_$CustomerPointLoaderStateImpl(
customerPoint: null == customerPoint
? _value.customerPoint
: customerPoint // ignore: cast_nullable_to_non_nullable
as CustomerPoint,
failureOptionCustomerPoint: null == failureOptionCustomerPoint
? _value.failureOptionCustomerPoint
: failureOptionCustomerPoint // ignore: cast_nullable_to_non_nullable
as Option<CustomerFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$CustomerPointLoaderStateImpl implements _CustomerPointLoaderState {
const _$CustomerPointLoaderStateImpl({
required this.customerPoint,
required this.failureOptionCustomerPoint,
this.isFetching = false,
});
@override
final CustomerPoint customerPoint;
@override
final Option<CustomerFailure> failureOptionCustomerPoint;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'CustomerPointLoaderState(customerPoint: $customerPoint, failureOptionCustomerPoint: $failureOptionCustomerPoint, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CustomerPointLoaderStateImpl &&
(identical(other.customerPoint, customerPoint) ||
other.customerPoint == customerPoint) &&
(identical(
other.failureOptionCustomerPoint,
failureOptionCustomerPoint,
) ||
other.failureOptionCustomerPoint ==
failureOptionCustomerPoint) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode => Object.hash(
runtimeType,
customerPoint,
failureOptionCustomerPoint,
isFetching,
);
/// Create a copy of CustomerPointLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CustomerPointLoaderStateImplCopyWith<_$CustomerPointLoaderStateImpl>
get copyWith =>
__$$CustomerPointLoaderStateImplCopyWithImpl<
_$CustomerPointLoaderStateImpl
>(this, _$identity);
}
abstract class _CustomerPointLoaderState implements CustomerPointLoaderState {
const factory _CustomerPointLoaderState({
required final CustomerPoint customerPoint,
required final Option<CustomerFailure> failureOptionCustomerPoint,
final bool isFetching,
}) = _$CustomerPointLoaderStateImpl;
@override
CustomerPoint get customerPoint;
@override
Option<CustomerFailure> get failureOptionCustomerPoint;
@override
bool get isFetching;
/// Create a copy of CustomerPointLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CustomerPointLoaderStateImplCopyWith<_$CustomerPointLoaderStateImpl>
get copyWith => throw _privateConstructorUsedError;
}
@@ -0,0 +1,6 @@
part of 'customer_point_loader_bloc.dart';
@freezed
class CustomerPointLoaderEvent with _$CustomerPointLoaderEvent {
const factory CustomerPointLoaderEvent.fetched() = _Fetched;
}
@@ -0,0 +1,15 @@
part of 'customer_point_loader_bloc.dart';
@freezed
class CustomerPointLoaderState with _$CustomerPointLoaderState {
const factory CustomerPointLoaderState({
required CustomerPoint customerPoint,
required Option<CustomerFailure> failureOptionCustomerPoint,
@Default(false) bool isFetching,
}) = _CustomerPointLoaderState;
factory CustomerPointLoaderState.initial() => CustomerPointLoaderState(
customerPoint: CustomerPoint.empty(),
failureOptionCustomerPoint: none(),
);
}
@@ -0,0 +1,42 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/game/game.dart';
part 'ferris_wheel_loader_event.dart';
part 'ferris_wheel_loader_state.dart';
part 'ferris_wheel_loader_bloc.freezed.dart';
@injectable
class FerrisWheelLoaderBloc
extends Bloc<FerrisWheelLoaderEvent, FerrisWheelLoaderState> {
final IGameRepository _repository;
FerrisWheelLoaderBloc(this._repository)
: super(FerrisWheelLoaderState.initial()) {
on<FerrisWheelLoaderEvent>(_onFerrisWheelLoaderEvent);
}
Future<void> _onFerrisWheelLoaderEvent(
FerrisWheelLoaderEvent event,
Emitter<FerrisWheelLoaderState> emit,
) {
return event.map(
fetched: (e) async {
emit(
state.copyWith(isFetching: true, failureOptionFerrisWheel: none()),
);
final result = await _repository.ferrisWheel();
var data = result.fold(
(f) => state.copyWith(failureOptionFerrisWheel: optionOf(f)),
(ferrisWheel) => state.copyWith(ferrisWheel: ferrisWheel),
);
emit(data.copyWith(isFetching: false));
},
);
}
}
@@ -0,0 +1,388 @@
// 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 'ferris_wheel_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
/// @nodoc
mixin _$FerrisWheelLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $FerrisWheelLoaderEventCopyWith<$Res> {
factory $FerrisWheelLoaderEventCopyWith(
FerrisWheelLoaderEvent value,
$Res Function(FerrisWheelLoaderEvent) then,
) = _$FerrisWheelLoaderEventCopyWithImpl<$Res, FerrisWheelLoaderEvent>;
}
/// @nodoc
class _$FerrisWheelLoaderEventCopyWithImpl<
$Res,
$Val extends FerrisWheelLoaderEvent
>
implements $FerrisWheelLoaderEventCopyWith<$Res> {
_$FerrisWheelLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of FerrisWheelLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$FerrisWheelLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of FerrisWheelLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl();
@override
String toString() {
return 'FerrisWheelLoaderEvent.fetched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({required TResult Function() fetched}) {
return fetched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched}) {
return fetched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements FerrisWheelLoaderEvent {
const factory _Fetched() = _$FetchedImpl;
}
/// @nodoc
mixin _$FerrisWheelLoaderState {
Game get ferrisWheel => throw _privateConstructorUsedError;
Option<GameFailure> get failureOptionFerrisWheel =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of FerrisWheelLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$FerrisWheelLoaderStateCopyWith<FerrisWheelLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $FerrisWheelLoaderStateCopyWith<$Res> {
factory $FerrisWheelLoaderStateCopyWith(
FerrisWheelLoaderState value,
$Res Function(FerrisWheelLoaderState) then,
) = _$FerrisWheelLoaderStateCopyWithImpl<$Res, FerrisWheelLoaderState>;
@useResult
$Res call({
Game ferrisWheel,
Option<GameFailure> failureOptionFerrisWheel,
bool isFetching,
});
$GameCopyWith<$Res> get ferrisWheel;
}
/// @nodoc
class _$FerrisWheelLoaderStateCopyWithImpl<
$Res,
$Val extends FerrisWheelLoaderState
>
implements $FerrisWheelLoaderStateCopyWith<$Res> {
_$FerrisWheelLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of FerrisWheelLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? ferrisWheel = null,
Object? failureOptionFerrisWheel = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
ferrisWheel: null == ferrisWheel
? _value.ferrisWheel
: ferrisWheel // ignore: cast_nullable_to_non_nullable
as Game,
failureOptionFerrisWheel: null == failureOptionFerrisWheel
? _value.failureOptionFerrisWheel
: failureOptionFerrisWheel // ignore: cast_nullable_to_non_nullable
as Option<GameFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of FerrisWheelLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$GameCopyWith<$Res> get ferrisWheel {
return $GameCopyWith<$Res>(_value.ferrisWheel, (value) {
return _then(_value.copyWith(ferrisWheel: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$FerrisWheelLoaderStateImplCopyWith<$Res>
implements $FerrisWheelLoaderStateCopyWith<$Res> {
factory _$$FerrisWheelLoaderStateImplCopyWith(
_$FerrisWheelLoaderStateImpl value,
$Res Function(_$FerrisWheelLoaderStateImpl) then,
) = __$$FerrisWheelLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
Game ferrisWheel,
Option<GameFailure> failureOptionFerrisWheel,
bool isFetching,
});
@override
$GameCopyWith<$Res> get ferrisWheel;
}
/// @nodoc
class __$$FerrisWheelLoaderStateImplCopyWithImpl<$Res>
extends
_$FerrisWheelLoaderStateCopyWithImpl<$Res, _$FerrisWheelLoaderStateImpl>
implements _$$FerrisWheelLoaderStateImplCopyWith<$Res> {
__$$FerrisWheelLoaderStateImplCopyWithImpl(
_$FerrisWheelLoaderStateImpl _value,
$Res Function(_$FerrisWheelLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of FerrisWheelLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? ferrisWheel = null,
Object? failureOptionFerrisWheel = null,
Object? isFetching = null,
}) {
return _then(
_$FerrisWheelLoaderStateImpl(
ferrisWheel: null == ferrisWheel
? _value.ferrisWheel
: ferrisWheel // ignore: cast_nullable_to_non_nullable
as Game,
failureOptionFerrisWheel: null == failureOptionFerrisWheel
? _value.failureOptionFerrisWheel
: failureOptionFerrisWheel // ignore: cast_nullable_to_non_nullable
as Option<GameFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$FerrisWheelLoaderStateImpl implements _FerrisWheelLoaderState {
const _$FerrisWheelLoaderStateImpl({
required this.ferrisWheel,
required this.failureOptionFerrisWheel,
this.isFetching = false,
});
@override
final Game ferrisWheel;
@override
final Option<GameFailure> failureOptionFerrisWheel;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'FerrisWheelLoaderState(ferrisWheel: $ferrisWheel, failureOptionFerrisWheel: $failureOptionFerrisWheel, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$FerrisWheelLoaderStateImpl &&
(identical(other.ferrisWheel, ferrisWheel) ||
other.ferrisWheel == ferrisWheel) &&
(identical(
other.failureOptionFerrisWheel,
failureOptionFerrisWheel,
) ||
other.failureOptionFerrisWheel == failureOptionFerrisWheel) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode => Object.hash(
runtimeType,
ferrisWheel,
failureOptionFerrisWheel,
isFetching,
);
/// Create a copy of FerrisWheelLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$FerrisWheelLoaderStateImplCopyWith<_$FerrisWheelLoaderStateImpl>
get copyWith =>
__$$FerrisWheelLoaderStateImplCopyWithImpl<_$FerrisWheelLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _FerrisWheelLoaderState implements FerrisWheelLoaderState {
const factory _FerrisWheelLoaderState({
required final Game ferrisWheel,
required final Option<GameFailure> failureOptionFerrisWheel,
final bool isFetching,
}) = _$FerrisWheelLoaderStateImpl;
@override
Game get ferrisWheel;
@override
Option<GameFailure> get failureOptionFerrisWheel;
@override
bool get isFetching;
/// Create a copy of FerrisWheelLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$FerrisWheelLoaderStateImplCopyWith<_$FerrisWheelLoaderStateImpl>
get copyWith => throw _privateConstructorUsedError;
}
@@ -0,0 +1,6 @@
part of 'ferris_wheel_loader_bloc.dart';
@freezed
class FerrisWheelLoaderEvent with _$FerrisWheelLoaderEvent {
const factory FerrisWheelLoaderEvent.fetched() = _Fetched;
}
@@ -0,0 +1,15 @@
part of 'ferris_wheel_loader_bloc.dart';
@freezed
class FerrisWheelLoaderState with _$FerrisWheelLoaderState {
const factory FerrisWheelLoaderState({
required Game ferrisWheel,
required Option<GameFailure> failureOptionFerrisWheel,
@Default(false) bool isFetching,
}) = _FerrisWheelLoaderState;
factory FerrisWheelLoaderState.initial() => FerrisWheelLoaderState(
ferrisWheel: Game.empty(),
failureOptionFerrisWheel: none(),
);
}
+1
View File
@@ -27,6 +27,7 @@ class ApiClient {
ApiClient(this._dio, this._env) { ApiClient(this._dio, this._env) {
_dio.options.baseUrl = _env.baseUrl; _dio.options.baseUrl = _env.baseUrl;
_dio.options.connectTimeout = const Duration(seconds: 20); _dio.options.connectTimeout = const Duration(seconds: 20);
_dio.options.validateStatus = (status) => true;
_dio.interceptors.add(BadNetworkErrorInterceptor()); _dio.interceptors.add(BadNetworkErrorInterceptor());
_dio.interceptors.add(BadRequestErrorInterceptor()); _dio.interceptors.add(BadRequestErrorInterceptor());
_dio.interceptors.add(InternalServerErrorInterceptor()); _dio.interceptors.add(InternalServerErrorInterceptor());
@@ -1,15 +1,40 @@
import 'package:dio/dio.dart'; import 'dart:developer';
import 'package:auto_route/auto_route.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../presentation/router/app_router.gr.dart';
import '../../constant/local_storage_key.dart';
import '../errors/unauthorized_error.dart'; import '../errors/unauthorized_error.dart';
class UnauthorizedInterceptor extends Interceptor { class UnauthorizedInterceptor extends Interceptor {
static final GlobalKey<NavigatorState> navigatorKey =
GlobalKey<NavigatorState>();
@override @override
void onError(DioException err, ErrorInterceptorHandler handler) { void onError(DioException err, ErrorInterceptorHandler handler) async {
if (err.response?.statusCode == 401 || if (err.response?.statusCode == 401 ||
err.response?.statusCode == 403 || err.response?.statusCode == 403 ||
err.response?.statusCode == 419) { err.response?.statusCode == 419) {
await _handleTokenExpired();
return super.onError(UnauthorizedError(err, null), handler); return super.onError(UnauthorizedError(err, null), handler);
} }
super.onError(err, handler); super.onError(err, handler);
} }
Future<void> _handleTokenExpired() async {
// Clear stored token
final prefs = await SharedPreferences.getInstance();
await prefs.remove(LocalStorageKey.token);
await prefs.remove(LocalStorageKey.user);
await prefs.clear(); // Optional: clear all user data
log('handleTokenExpired');
// Navigate to login page
final context = navigatorKey.currentContext;
if (context != null) {
// Option 1: Navigate and remove all previous routes
context.router.replaceAll([LoginRoute()]);
}
}
} }
+7 -1
View File
@@ -1,3 +1,9 @@
import '../../sample/sample_data.dart';
class AppConstant { class AppConstant {
static const String appName = ""; static const String appName = "Enaklo";
static const String coinName = "EnakCoin";
static const String poinName = "EnakPoin";
} }
MerchantModel merchant = merchants.first;
@@ -0,0 +1,4 @@
class LocalStorageKey {
static const token = 'token';
static const user = 'user';
}
+26
View File
@@ -0,0 +1,26 @@
import '../../presentation/components/assets/assets.gen.dart';
class Service {
Service({
required this.name,
required this.description,
required this.imagePath,
});
final String name;
final String imagePath;
final String description;
}
List<Service> services = [
Service(
name: 'Dine In',
description: 'Makan langsung di tempat',
imagePath: Assets.icons.dineIn.path,
),
Service(
name: 'Take Away',
description: 'Pesan dan bawa pulang',
imagePath: Assets.icons.takeaway.path,
),
];
@@ -0,0 +1,28 @@
part of 'extension.dart';
extension DoubleExt on double {
String get currencyFormatRpV2 => NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
).format(this);
}
extension StringX on String {
String get currencyFormatRp {
final parsedValue = int.tryParse(this) ?? 0;
return NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
).format(parsedValue);
}
}
extension IntegerExt on int {
String get currencyFormatRp => NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
).format(this);
}
+1 -1
View File
@@ -23,7 +23,7 @@ extension DateTimeIndonesia on DateTime {
/// Format: 13-08-2025 /// Format: 13-08-2025
String get toServerDate { String get toServerDate {
return DateFormat('dd-MM-yyyy', 'id_ID').format(this); return DateFormat('yyyy-MM-dd', 'id_ID').format(this);
} }
/// Format jam: 14:30 /// Format jam: 14:30
+2 -1
View File
@@ -3,11 +3,12 @@ import 'package:intl/intl.dart';
import '../../domain/auth/auth.dart'; import '../../domain/auth/auth.dart';
part 'date_extension.dart'; part 'date_extension.dart';
part 'currency_extension.dart';
extension StringExt on String { extension StringExt on String {
CheckPhoneStatus toCheckPhoneStatus() { CheckPhoneStatus toCheckPhoneStatus() {
switch (this) { switch (this) {
case 'NO_REGISTERED': case 'NOT_REGISTERED':
return CheckPhoneStatus.notRegistered; return CheckPhoneStatus.notRegistered;
case 'PASSWORD_REQUIRED': case 'PASSWORD_REQUIRED':
return CheckPhoneStatus.passwordRequired; return CheckPhoneStatus.passwordRequired;
+18
View File
@@ -1,4 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../injection.dart';
import '../constant/local_storage_key.dart';
void dismissKeyboard(BuildContext context) { void dismissKeyboard(BuildContext context) {
final currentFocus = FocusScope.of(context); final currentFocus = FocusScope.of(context);
@@ -6,3 +10,17 @@ void dismissKeyboard(BuildContext context) {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
} }
} }
String getNormalizePhone(String phoneNumber) {
final normalizedPhone = phoneNumber.startsWith('08')
? phoneNumber.replaceFirst('0', '')
: phoneNumber;
return '62$normalizedPhone';
}
Map<String, dynamic> getAuthorizationHeader() {
return {
'Authorization':
'Bearer ${getIt<SharedPreferences>().getString(LocalStorageKey.token)}',
};
}
+56 -92
View File
@@ -1,19 +1,21 @@
// wheel_painter.dart - Fixed implementation with consistent positioning
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../domain/game/game.dart';
import '../../presentation/pages/mini_games/ferris_wheel/data/model.dart';
import '../theme/theme.dart';
class WheelPainter extends CustomPainter { class WheelPainter extends CustomPainter {
final List<WheelSection> sections; final List<GamePrize> gamePrizes;
final Color Function(GamePrize prize, int index) getPrizeColor;
WheelPainter({required this.sections}); WheelPainter({required this.gamePrizes, required this.getPrizeColor});
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
if (gamePrizes.isEmpty) return;
final center = Offset(size.width / 2, size.height / 2); final center = Offset(size.width / 2, size.height / 2);
final radius = size.width / 2; final radius = size.width / 2;
final sectionAngle = 2 * math.pi / sections.length; final sectionAngle = 2 * math.pi / gamePrizes.length;
// Draw outer white border // Draw outer white border
final outerBorderPaint = Paint() final outerBorderPaint = Paint()
@@ -33,13 +35,15 @@ class WheelPainter extends CustomPainter {
..style = PaintingStyle.fill; ..style = PaintingStyle.fill;
canvas.drawCircle(center, radius - 20, innerWhitePaint); canvas.drawCircle(center, radius - 20, innerWhitePaint);
// Draw sections // Draw sections - KONSISTEN dengan logic spin
for (int i = 0; i < sections.length; i++) { for (int i = 0; i < gamePrizes.length; i++) {
final startAngle = i * sectionAngle - math.pi / 2; final prize = gamePrizes[i];
// Section 0 di top (-Ď€/2), section 1 di kanan atas, dst (clockwise)
final startAngle = (-math.pi / 2) + (i * sectionAngle);
// Section background // Section background
final sectionPaint = Paint() final sectionPaint = Paint()
..color = sections[i].color ..color = getPrizeColor(prize, i)
..style = PaintingStyle.fill; ..style = PaintingStyle.fill;
canvas.drawArc( canvas.drawArc(
@@ -50,82 +54,67 @@ class WheelPainter extends CustomPainter {
sectionPaint, sectionPaint,
); );
// Draw icon in each section
final iconAngle = startAngle + sectionAngle / 2;
final iconPosition = Offset(
center.dx + (radius - 60) * math.cos(iconAngle),
center.dy + (radius - 60) * math.sin(iconAngle),
);
// Draw icon background circle
final iconBgPaint = Paint()
..color = Colors.white
..style = PaintingStyle.fill;
canvas.drawCircle(iconPosition, 16, iconBgPaint);
// Save canvas state for icon drawing
canvas.save();
canvas.translate(iconPosition.dx, iconPosition.dy);
// Draw icon using TextPainter to simulate Icon widget
final iconText = _getIconText(sections[i].icon);
final iconTextPainter = TextPainter(
text: TextSpan(
text: iconText,
style: TextStyle(
fontFamily: 'MaterialIcons',
fontSize: 20,
color: sections[i].color,
fontWeight: FontWeight.normal,
),
),
textDirection: TextDirection.ltr,
);
iconTextPainter.layout();
iconTextPainter.paint(
canvas,
Offset(-iconTextPainter.width / 2, -iconTextPainter.height / 2),
);
canvas.restore();
// Draw prize text // Draw prize text
final textAngle = startAngle + sectionAngle / 2; final textAngle = startAngle + sectionAngle / 2;
final textPosition = Offset( final textPosition = Offset(
center.dx + (radius - 100) * math.cos(textAngle), center.dx + (radius - 80) * math.cos(textAngle),
center.dy + (radius - 100) * math.sin(textAngle), center.dy + (radius - 80) * math.sin(textAngle),
); );
// Save canvas state for text rotation
canvas.save(); canvas.save();
canvas.translate(textPosition.dx, textPosition.dy); canvas.translate(textPosition.dx, textPosition.dy);
canvas.rotate(textAngle + math.pi / 2); canvas.rotate(textAngle + math.pi / 2);
final textPainter = TextPainter( final textPainter = TextPainter(
text: TextSpan( text: TextSpan(
text: sections[i].prize, text: prize.name,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 10, fontSize: 12,
fontWeight: FontWeight.bold,
),
),
textDirection: TextDirection.ltr,
textAlign: TextAlign.center,
);
textPainter.layout(maxWidth: 100);
textPainter.paint(
canvas,
Offset(-textPainter.width / 2, -textPainter.height / 2),
);
canvas.restore();
// DEBUG: Draw section number
final numberPosition = Offset(
center.dx + (radius - 50) * math.cos(textAngle),
center.dy + (radius - 50) * math.sin(textAngle),
);
canvas.drawCircle(numberPosition, 15, Paint()..color = Colors.white);
final numberPainter = TextPainter(
text: TextSpan(
text: i.toString(),
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
); );
textPainter.layout(); numberPainter.layout();
textPainter.paint( numberPainter.paint(
canvas, canvas,
Offset(-textPainter.width / 2, -textPainter.height / 2), Offset(
numberPosition.dx - numberPainter.width / 2,
numberPosition.dy - numberPainter.height / 2,
),
); );
canvas.restore();
} }
// Draw white dots around the outer edge // Draw white dots
final dotPaint = Paint() final dotPaint = Paint()
..color = Colors.white ..color = Colors.white
..style = PaintingStyle.fill; ..style = PaintingStyle.fill;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
final dotAngle = (2 * math.pi / 24) * i; final dotAngle = (2 * math.pi / 24) * i;
final dotPosition = Offset( final dotPosition = Offset(
@@ -137,15 +126,14 @@ class WheelPainter extends CustomPainter {
// Draw section dividers // Draw section dividers
final dividerPaint = Paint() final dividerPaint = Paint()
..color = AppColor.white ..color = Colors.white
..style = PaintingStyle.stroke ..style = PaintingStyle.stroke
..strokeWidth = 2; ..strokeWidth = 2;
for (int i = 0; i < gamePrizes.length; i++) {
for (int i = 0; i < sections.length; i++) { final angle = (-math.pi / 2) + (i * sectionAngle);
final angle = i * sectionAngle - math.pi / 2;
final lineStart = Offset( final lineStart = Offset(
center.dx + (radius - 130) * math.cos(angle), center.dx + (radius - 110) * math.cos(angle),
center.dy + (radius - 130) * math.sin(angle), center.dy + (radius - 110) * math.sin(angle),
); );
final lineEnd = Offset( final lineEnd = Offset(
center.dx + (radius - 22) * math.cos(angle), center.dx + (radius - 22) * math.cos(angle),
@@ -155,30 +143,6 @@ class WheelPainter extends CustomPainter {
} }
} }
String _getIconText(IconData icon) {
// Convert IconData to Unicode string for drawing
switch (icon.codePoint) {
case 0xe8f4: // Icons.visibility
return String.fromCharCode(0xe8f4);
case 0xe8f5: // Icons.visibility_off
return String.fromCharCode(0xe8f5);
case 0xe850: // Icons.account_balance_wallet
return String.fromCharCode(0xe850);
case 0xe151: // Icons.card_giftcard
return String.fromCharCode(0xe151);
case 0xe5d5: // Icons.refresh
return String.fromCharCode(0xe5d5);
case 0xe263: // Icons.attach_money
return String.fromCharCode(0xe263);
case 0xe8a1: // Icons.redeem
return String.fromCharCode(0xe8a1);
case 0xe57d: // Icons.monetization_on
return String.fromCharCode(0xe57d);
default:
return String.fromCharCode(0xe87c); // Default star icon
}
}
@override @override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false; bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
} }
+5 -1
View File
@@ -1,3 +1,7 @@
part of 'theme.dart'; part of 'theme.dart';
class AppValue {} class AppValue {
static const double padding = 16;
static const double margin = 16;
static const double borderRadius = 12;
}
+35 -2
View File
@@ -16,12 +16,34 @@ class ThemeApp {
fontFamily: FontFamily.quicksand, fontFamily: FontFamily.quicksand,
primaryColor: AppColor.primary, primaryColor: AppColor.primary,
scaffoldBackgroundColor: AppColor.white, scaffoldBackgroundColor: AppColor.white,
datePickerTheme: DatePickerThemeData(
backgroundColor: AppColor.white,
todayBackgroundColor: MaterialStateProperty.resolveWith<Color?>((states) {
if (states.contains(MaterialState.selected)) {
return AppColor.primary; // warna background tanggal terpilih
}
return null; // default
}),
todayBorder: BorderSide(color: AppColor.primary, width: 1),
dayBackgroundColor: MaterialStateProperty.resolveWith<Color?>((states) {
if (states.contains(MaterialState.selected)) {
return AppColor.primary; // warna background tanggal terpilih
}
return null; // default
}),
dayForegroundColor: MaterialStateProperty.resolveWith<Color?>((states) {
if (states.contains(MaterialState.selected)) {
return AppColor.white; // warna text tanggal terpilih
}
return null; // default
}),
),
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
backgroundColor: AppColor.white, backgroundColor: AppColor.white,
foregroundColor: AppColor.textPrimary, foregroundColor: AppColor.textPrimary,
elevation: 0, elevation: 0,
titleTextStyle: AppStyle.xl.copyWith( titleTextStyle: AppStyle.xl.copyWith(
color: AppColor.primary, color: AppColor.textPrimary,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
centerTitle: true, centerTitle: true,
@@ -33,7 +55,18 @@ class ThemeApp {
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
foregroundColor: Colors.white, foregroundColor: Colors.white,
elevation: 0, elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppValue.borderRadius),
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColor.primary,
shape: RoundedRectangleBorder(
side: BorderSide(color: AppColor.border),
borderRadius: BorderRadiusGeometry.circular(AppValue.borderRadius),
),
), ),
), ),
inputDecorationTheme: InputDecorationTheme( inputDecorationTheme: InputDecorationTheme(
+8 -2
View File
@@ -3,6 +3,12 @@ class ApiPath {
static String register = '/api/v1/customer-auth/register/start'; static String register = '/api/v1/customer-auth/register/start';
static String verify = '/api/v1/customer-auth/register/verify-otp'; static String verify = '/api/v1/customer-auth/register/verify-otp';
static String setPassword = '/api/v1/customer-auth/register/set-password'; static String setPassword = '/api/v1/customer-auth/register/set-password';
static String login = '/api/v1/customer-auth/register/login'; static String login = '/api/v1/customer-auth/login';
static String resend = '/api/v1/customer-auth/register/resend-otp'; static String resend = '/api/v1/customer-auth/resend-otp';
// Marketing
static String ferrisWheel = '/api/v1/customer/ferris-wheel';
// Customer
static String customerPoint = '/api/v1/customer/points';
} }
+16 -16
View File
@@ -17,7 +17,7 @@ final _privateConstructorUsedError = UnsupportedError(
/// @nodoc /// @nodoc
mixin _$CheckPhone { mixin _$CheckPhone {
String get status => throw _privateConstructorUsedError; CheckPhoneStatus get status => throw _privateConstructorUsedError;
String get message => throw _privateConstructorUsedError; String get message => throw _privateConstructorUsedError;
String get phoneNumber => throw _privateConstructorUsedError; String get phoneNumber => throw _privateConstructorUsedError;
@@ -35,7 +35,7 @@ abstract class $CheckPhoneCopyWith<$Res> {
$Res Function(CheckPhone) then, $Res Function(CheckPhone) then,
) = _$CheckPhoneCopyWithImpl<$Res, CheckPhone>; ) = _$CheckPhoneCopyWithImpl<$Res, CheckPhone>;
@useResult @useResult
$Res call({String status, String message, String phoneNumber}); $Res call({CheckPhoneStatus status, String message, String phoneNumber});
} }
/// @nodoc /// @nodoc
@@ -62,7 +62,7 @@ class _$CheckPhoneCopyWithImpl<$Res, $Val extends CheckPhone>
status: null == status status: null == status
? _value.status ? _value.status
: status // ignore: cast_nullable_to_non_nullable : status // ignore: cast_nullable_to_non_nullable
as String, as CheckPhoneStatus,
message: null == message message: null == message
? _value.message ? _value.message
: message // ignore: cast_nullable_to_non_nullable : message // ignore: cast_nullable_to_non_nullable
@@ -86,7 +86,7 @@ abstract class _$$CheckPhoneImplCopyWith<$Res>
) = __$$CheckPhoneImplCopyWithImpl<$Res>; ) = __$$CheckPhoneImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call({String status, String message, String phoneNumber}); $Res call({CheckPhoneStatus status, String message, String phoneNumber});
} }
/// @nodoc /// @nodoc
@@ -112,7 +112,7 @@ class __$$CheckPhoneImplCopyWithImpl<$Res>
status: null == status status: null == status
? _value.status ? _value.status
: status // ignore: cast_nullable_to_non_nullable : status // ignore: cast_nullable_to_non_nullable
as String, as CheckPhoneStatus,
message: null == message message: null == message
? _value.message ? _value.message
: message // ignore: cast_nullable_to_non_nullable : message // ignore: cast_nullable_to_non_nullable
@@ -136,7 +136,7 @@ class _$CheckPhoneImpl implements _CheckPhone {
}); });
@override @override
final String status; final CheckPhoneStatus status;
@override @override
final String message; final String message;
@override @override
@@ -172,13 +172,13 @@ class _$CheckPhoneImpl implements _CheckPhone {
abstract class _CheckPhone implements CheckPhone { abstract class _CheckPhone implements CheckPhone {
const factory _CheckPhone({ const factory _CheckPhone({
required final String status, required final CheckPhoneStatus status,
required final String message, required final String message,
required final String phoneNumber, required final String phoneNumber,
}) = _$CheckPhoneImpl; }) = _$CheckPhoneImpl;
@override @override
String get status; CheckPhoneStatus get status;
@override @override
String get message; String get message;
@override @override
@@ -1035,7 +1035,7 @@ abstract class _User implements User {
/// @nodoc /// @nodoc
mixin _$Resend { mixin _$Resend {
String get status => throw _privateConstructorUsedError; ResendStatus get status => throw _privateConstructorUsedError;
String get message => throw _privateConstructorUsedError; String get message => throw _privateConstructorUsedError;
String get otpToken => throw _privateConstructorUsedError; String get otpToken => throw _privateConstructorUsedError;
int get expiresIn => throw _privateConstructorUsedError; int get expiresIn => throw _privateConstructorUsedError;
@@ -1053,7 +1053,7 @@ abstract class $ResendCopyWith<$Res> {
_$ResendCopyWithImpl<$Res, Resend>; _$ResendCopyWithImpl<$Res, Resend>;
@useResult @useResult
$Res call({ $Res call({
String status, ResendStatus status,
String message, String message,
String otpToken, String otpToken,
int expiresIn, int expiresIn,
@@ -1087,7 +1087,7 @@ class _$ResendCopyWithImpl<$Res, $Val extends Resend>
status: null == status status: null == status
? _value.status ? _value.status
: status // ignore: cast_nullable_to_non_nullable : status // ignore: cast_nullable_to_non_nullable
as String, as ResendStatus,
message: null == message message: null == message
? _value.message ? _value.message
: message // ignore: cast_nullable_to_non_nullable : message // ignore: cast_nullable_to_non_nullable
@@ -1119,7 +1119,7 @@ abstract class _$$ResendImplCopyWith<$Res> implements $ResendCopyWith<$Res> {
@override @override
@useResult @useResult
$Res call({ $Res call({
String status, ResendStatus status,
String message, String message,
String otpToken, String otpToken,
int expiresIn, int expiresIn,
@@ -1152,7 +1152,7 @@ class __$$ResendImplCopyWithImpl<$Res>
status: null == status status: null == status
? _value.status ? _value.status
: status // ignore: cast_nullable_to_non_nullable : status // ignore: cast_nullable_to_non_nullable
as String, as ResendStatus,
message: null == message message: null == message
? _value.message ? _value.message
: message // ignore: cast_nullable_to_non_nullable : message // ignore: cast_nullable_to_non_nullable
@@ -1186,7 +1186,7 @@ class _$ResendImpl implements _Resend {
}); });
@override @override
final String status; final ResendStatus status;
@override @override
final String message; final String message;
@override @override
@@ -1237,7 +1237,7 @@ class _$ResendImpl implements _Resend {
abstract class _Resend implements Resend { abstract class _Resend implements Resend {
const factory _Resend({ const factory _Resend({
required final String status, required final ResendStatus status,
required final String message, required final String message,
required final String otpToken, required final String otpToken,
required final int expiresIn, required final int expiresIn,
@@ -1245,7 +1245,7 @@ abstract class _Resend implements Resend {
}) = _$ResendImpl; }) = _$ResendImpl;
@override @override
String get status; ResendStatus get status;
@override @override
String get message; String get message;
@override @override
@@ -3,11 +3,14 @@ part of '../auth.dart';
@freezed @freezed
class CheckPhone with _$CheckPhone { class CheckPhone with _$CheckPhone {
const factory CheckPhone({ const factory CheckPhone({
required String status, required CheckPhoneStatus status,
required String message, required String message,
required String phoneNumber, required String phoneNumber,
}) = _CheckPhone; }) = _CheckPhone;
factory CheckPhone.empty() => factory CheckPhone.empty() => CheckPhone(
const CheckPhone(status: '', message: '', phoneNumber: ''); status: CheckPhoneStatus.unknown,
message: '',
phoneNumber: '',
);
} }
+3 -3
View File
@@ -3,15 +3,15 @@ part of '../auth.dart';
@freezed @freezed
class Resend with _$Resend { class Resend with _$Resend {
const factory Resend({ const factory Resend({
required String status, required ResendStatus status,
required String message, required String message,
required String otpToken, required String otpToken,
required int expiresIn, required int expiresIn,
required int nextResendIn, required int nextResendIn,
}) = _Resend; }) = _Resend;
factory Resend.empty() => const Resend( factory Resend.empty() => Resend(
status: '', status: ResendStatus.unknown,
message: '', message: '',
otpToken: '', otpToken: '',
expiresIn: 0, expiresIn: 0,
@@ -31,4 +31,10 @@ abstract class IAuthRepository {
required String phoneNumber, required String phoneNumber,
required String purpose, required String purpose,
}); });
Future<bool> hasToken();
Future<Either<AuthFailure, User>> currentUser();
Future<Either<AuthFailure, Unit>> logout();
} }
+10
View File
@@ -0,0 +1,10 @@
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'customer.freezed.dart';
part 'entities/customer_point_entity.dart';
part 'failures/customer_failures.dart';
part 'repositories/i_customer_repository.dart';
+713
View File
@@ -0,0 +1,713 @@
// 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>(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 _$CustomerPoint {
String get status => throw _privateConstructorUsedError;
String get message => throw _privateConstructorUsedError;
int get totalPoints => throw _privateConstructorUsedError;
String get lastUpdated => throw _privateConstructorUsedError;
/// Create a copy of CustomerPoint
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CustomerPointCopyWith<CustomerPoint> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CustomerPointCopyWith<$Res> {
factory $CustomerPointCopyWith(
CustomerPoint value,
$Res Function(CustomerPoint) then,
) = _$CustomerPointCopyWithImpl<$Res, CustomerPoint>;
@useResult
$Res call({
String status,
String message,
int totalPoints,
String lastUpdated,
});
}
/// @nodoc
class _$CustomerPointCopyWithImpl<$Res, $Val extends CustomerPoint>
implements $CustomerPointCopyWith<$Res> {
_$CustomerPointCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CustomerPoint
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? status = null,
Object? message = null,
Object? totalPoints = null,
Object? lastUpdated = null,
}) {
return _then(
_value.copyWith(
status: null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String,
message: null == message
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String,
totalPoints: null == totalPoints
? _value.totalPoints
: totalPoints // ignore: cast_nullable_to_non_nullable
as int,
lastUpdated: null == lastUpdated
? _value.lastUpdated
: lastUpdated // ignore: cast_nullable_to_non_nullable
as String,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$CustomerPointImplCopyWith<$Res>
implements $CustomerPointCopyWith<$Res> {
factory _$$CustomerPointImplCopyWith(
_$CustomerPointImpl value,
$Res Function(_$CustomerPointImpl) then,
) = __$$CustomerPointImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
String status,
String message,
int totalPoints,
String lastUpdated,
});
}
/// @nodoc
class __$$CustomerPointImplCopyWithImpl<$Res>
extends _$CustomerPointCopyWithImpl<$Res, _$CustomerPointImpl>
implements _$$CustomerPointImplCopyWith<$Res> {
__$$CustomerPointImplCopyWithImpl(
_$CustomerPointImpl _value,
$Res Function(_$CustomerPointImpl) _then,
) : super(_value, _then);
/// Create a copy of CustomerPoint
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? status = null,
Object? message = null,
Object? totalPoints = null,
Object? lastUpdated = null,
}) {
return _then(
_$CustomerPointImpl(
status: null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String,
message: null == message
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String,
totalPoints: null == totalPoints
? _value.totalPoints
: totalPoints // ignore: cast_nullable_to_non_nullable
as int,
lastUpdated: null == lastUpdated
? _value.lastUpdated
: lastUpdated // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$CustomerPointImpl implements _CustomerPoint {
const _$CustomerPointImpl({
required this.status,
required this.message,
required this.totalPoints,
required this.lastUpdated,
});
@override
final String status;
@override
final String message;
@override
final int totalPoints;
@override
final String lastUpdated;
@override
String toString() {
return 'CustomerPoint(status: $status, message: $message, totalPoints: $totalPoints, lastUpdated: $lastUpdated)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CustomerPointImpl &&
(identical(other.status, status) || other.status == status) &&
(identical(other.message, message) || other.message == message) &&
(identical(other.totalPoints, totalPoints) ||
other.totalPoints == totalPoints) &&
(identical(other.lastUpdated, lastUpdated) ||
other.lastUpdated == lastUpdated));
}
@override
int get hashCode =>
Object.hash(runtimeType, status, message, totalPoints, lastUpdated);
/// Create a copy of CustomerPoint
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CustomerPointImplCopyWith<_$CustomerPointImpl> get copyWith =>
__$$CustomerPointImplCopyWithImpl<_$CustomerPointImpl>(this, _$identity);
}
abstract class _CustomerPoint implements CustomerPoint {
const factory _CustomerPoint({
required final String status,
required final String message,
required final int totalPoints,
required final String lastUpdated,
}) = _$CustomerPointImpl;
@override
String get status;
@override
String get message;
@override
int get totalPoints;
@override
String get lastUpdated;
/// Create a copy of CustomerPoint
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CustomerPointImplCopyWith<_$CustomerPointImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$CustomerFailure {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_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<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return serverError(failure);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return serverError?.call(failure);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (serverError != null) {
return serverError(failure);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return serverError(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return serverError?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_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<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return unexpectedError();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return unexpectedError?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (unexpectedError != null) {
return unexpectedError();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return unexpectedError(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return unexpectedError?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_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 _$$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<TResult extends Object?>({
required TResult Function(ApiFailure failure) serverError,
required TResult Function() unexpectedError,
required TResult Function(String erroMessage) dynamicErrorMessage,
}) {
return dynamicErrorMessage(erroMessage);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(ApiFailure failure)? serverError,
TResult? Function()? unexpectedError,
TResult? Function(String erroMessage)? dynamicErrorMessage,
}) {
return dynamicErrorMessage?.call(erroMessage);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(ApiFailure failure)? serverError,
TResult Function()? unexpectedError,
TResult Function(String erroMessage)? dynamicErrorMessage,
required TResult orElse(),
}) {
if (dynamicErrorMessage != null) {
return dynamicErrorMessage(erroMessage);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ServerError value) serverError,
required TResult Function(_UnexpectedError value) unexpectedError,
required TResult Function(_DynamicErrorMessage value) dynamicErrorMessage,
}) {
return dynamicErrorMessage(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ServerError value)? serverError,
TResult? Function(_UnexpectedError value)? unexpectedError,
TResult? Function(_DynamicErrorMessage value)? dynamicErrorMessage,
}) {
return dynamicErrorMessage?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ServerError value)? serverError,
TResult Function(_UnexpectedError value)? unexpectedError,
TResult Function(_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;
}
@@ -0,0 +1,18 @@
part of '../customer.dart';
@freezed
class CustomerPoint with _$CustomerPoint {
const factory CustomerPoint({
required String status,
required String message,
required int totalPoints,
required String lastUpdated,
}) = _CustomerPoint;
factory CustomerPoint.empty() => const CustomerPoint(
status: '',
message: '',
totalPoints: 0,
lastUpdated: '',
);
}
@@ -0,0 +1,9 @@
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.dynamicErrorMessage(String erroMessage) =
_DynamicErrorMessage;
}
@@ -0,0 +1,5 @@
part of '../customer.dart';
abstract class ICustomerRepository {
Future<Either<CustomerFailure, CustomerPoint>> getPoints();
}
+26
View File
@@ -0,0 +1,26 @@
part of '../game.dart';
@freezed
class Game with _$Game {
const factory Game({
required String id,
required String name,
required String type,
required bool isActive,
required Map<String, dynamic> metadata,
required List<GamePrize> prizes,
required String createdAt,
required String updatedAt,
}) = _Game;
factory Game.empty() => const Game(
id: '',
name: '',
type: '',
isActive: false,
metadata: {},
prizes: [],
createdAt: '',
updatedAt: '',
);
}
@@ -0,0 +1,22 @@
part of '../game.dart';
@freezed
class GamePrize with _$GamePrize {
const factory GamePrize({
required String id,
required String gameId,
required String name,
required Map<String, dynamic> metadata,
required String createdAt,
required String updatedAt,
}) = _GamePrize;
factory GamePrize.empty() => const GamePrize(
id: '',
gameId: '',
name: '',
metadata: {},
createdAt: '',
updatedAt: '',
);
}
@@ -0,0 +1,9 @@
part of '../game.dart';
@freezed
sealed class GameFailure with _$GameFailure {
const factory GameFailure.serverError(ApiFailure failure) = _ServerError;
const factory GameFailure.unexpectedError() = _UnexpectedError;
const factory GameFailure.dynamicErrorMessage(String erroMessage) =
_DynamicErrorMessage;
}
+11
View File
@@ -0,0 +1,11 @@
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'game.freezed.dart';
part 'entity/game_entity.dart';
part 'entity/game_prize_entity.dart';
part 'failures/game_failure.dart';
part 'repositories/i_game_repository.dart';
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,5 @@
part of '../game.dart';
abstract class IGameRepository {
Future<Either<GameFailure, Game>> ferrisWheel();
}
+3 -2
View File
@@ -9,12 +9,13 @@ abstract class Env {
@dev @dev
class DevEnv implements Env { class DevEnv implements Env {
@override @override
String get baseUrl => 'http://192.168.1.30:4000'; // example value // String get baseUrl => 'http://192.168.1.30:4000'; // example value
String get baseUrl => 'https://api-pos.apskel.id'; // example value
} }
@Injectable(as: Env) @Injectable(as: Env)
@prod @prod
class ProdEnv implements Env { class ProdEnv implements Env {
@override @override
String get baseUrl => 'https://enaklo-pos-be.altru.id'; String get baseUrl => 'https://api-pos.apskel.id';
} }
+1
View File
@@ -1,5 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/extension/extension.dart';
import '../../domain/auth/auth.dart'; import '../../domain/auth/auth.dart';
part 'auth_dtos.freezed.dart'; part 'auth_dtos.freezed.dart';
@@ -0,0 +1,60 @@
import 'dart:convert';
import 'dart:developer';
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../common/constant/local_storage_key.dart';
import '../../../domain/auth/auth.dart';
import '../auth_dtos.dart';
@injectable
class AuthLocalDataProvider {
final SharedPreferences _sharedPreferences;
final String _logName = 'AuthLocalDataProvider';
AuthLocalDataProvider(this._sharedPreferences);
Future<void> saveToken(String token) async {
await _sharedPreferences.setString(LocalStorageKey.token, token);
}
Future<String?> getToken() async {
return _sharedPreferences.getString(LocalStorageKey.token);
}
Future<void> deleteToken() async {
await _sharedPreferences.remove(LocalStorageKey.token);
}
Future<bool> hasToken() async {
return _sharedPreferences.containsKey(LocalStorageKey.token);
}
Future<void> saveCurrentUser(UserDto user) async {
final userJsonString = jsonEncode(user.toJson());
await _sharedPreferences.setString(LocalStorageKey.user, userJsonString);
}
Future<User> currentUser() async {
final userString = _sharedPreferences.getString(LocalStorageKey.user);
if (userString == null) return User.empty();
final Map<String, dynamic> userMap = jsonDecode(userString);
final userDto = UserDto.fromJson(userMap);
return userDto.toDomain();
}
Future<void> deleteCurrentUser() async {
await _sharedPreferences.remove(LocalStorageKey.user);
}
Future<void> deleteAllAuth() async {
try {
await _sharedPreferences.remove(LocalStorageKey.token);
await _sharedPreferences.remove(LocalStorageKey.user);
} catch (e) {
log('deleteAllAuthError', name: _logName, error: e);
}
}
}
@@ -41,6 +41,13 @@ class AuthRemoteDataProvider {
AuthFailure.dynamicErrorMessage('No. Telepon Tidak Boleh Kosong'), AuthFailure.dynamicErrorMessage('No. Telepon Tidak Boleh Kosong'),
); );
} }
if (response.data['errors'][0]['code'] == 304) {
return DC.error(
AuthFailure.dynamicErrorMessage(
response.data['errors'][0]['cause'],
),
);
}
} }
} }
@@ -154,12 +161,18 @@ class AuthRemoteDataProvider {
if (response.data['success'] == false) { if (response.data['success'] == false) {
if ((response.data['errors'] as List).isNotEmpty) { if ((response.data['errors'] as List).isNotEmpty) {
if (response.data['errors'][0]['code'] == "900") { if (response.data['errors'][0]['code'] == 900) {
return DC.error( return DC.error(
AuthFailure.dynamicErrorMessage( AuthFailure.dynamicErrorMessage(
'Invalid Registration, Lakukan kembali dari awal', 'Invalid Registration, Lakukan kembali dari awal',
), ),
); );
} else if (response.data['errors'][0]['code'] == "304") {
return DC.error(
AuthFailure.dynamicErrorMessage(
response.data['errors'][0]['cause'],
),
);
} else { } else {
return DC.error( return DC.error(
AuthFailure.dynamicErrorMessage( AuthFailure.dynamicErrorMessage(
@@ -198,7 +211,9 @@ class AuthRemoteDataProvider {
if ((response.data['errors'] as List).isNotEmpty) { if ((response.data['errors'] as List).isNotEmpty) {
if (response.data['errors'][0]['code'] == "900") { if (response.data['errors'][0]['code'] == "900") {
return DC.error( return DC.error(
AuthFailure.dynamicErrorMessage('Kamu Belum Terdaftar'), AuthFailure.dynamicErrorMessage(
response.data['errors'][0]['cause'],
),
); );
} else { } else {
return DC.error( return DC.error(
@@ -13,7 +13,7 @@ class CheckPhoneDto with _$CheckPhoneDto {
factory CheckPhoneDto.fromJson(Map<String, dynamic> json) => factory CheckPhoneDto.fromJson(Map<String, dynamic> json) =>
_$CheckPhoneDtoFromJson(json); _$CheckPhoneDtoFromJson(json);
CheckPhone toDomain() => CheckPhone( CheckPhone toDomain() => CheckPhone(
status: status ?? '', status: status?.toCheckPhoneStatus() ?? CheckPhoneStatus.unknown,
message: message ?? '', message: message ?? '',
phoneNumber: data?.phoneNumber ?? '', phoneNumber: data?.phoneNumber ?? '',
); );
+1 -1
View File
@@ -15,7 +15,7 @@ class ResendDto with _$ResendDto {
/// mapping ke domain /// mapping ke domain
Resend toDomain() => Resend( Resend toDomain() => Resend(
status: status ?? '', status: status?.toResendStatus() ?? ResendStatus.unknown,
message: message ?? '', message: message ?? '',
otpToken: data?.otpToken ?? '', otpToken: data?.otpToken ?? '',
expiresIn: data?.expiresIn ?? 0, expiresIn: data?.expiresIn ?? 0,
@@ -4,15 +4,17 @@ import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import '../../../domain/auth/auth.dart'; import '../../../domain/auth/auth.dart';
import '../datasources/local_data_provider.dart';
import '../datasources/remote_data_provider.dart'; import '../datasources/remote_data_provider.dart';
@Injectable(as: IAuthRepository) @Injectable(as: IAuthRepository)
class AuthRepository implements IAuthRepository { class AuthRepository implements IAuthRepository {
final AuthLocalDataProvider _localDataProvider;
final AuthRemoteDataProvider _remoteDataProvider; final AuthRemoteDataProvider _remoteDataProvider;
final String _logName = 'AuthRepository'; final String _logName = 'AuthRepository';
AuthRepository(this._remoteDataProvider); AuthRepository(this._remoteDataProvider, this._localDataProvider);
@override @override
Future<Either<AuthFailure, CheckPhone>> checkPhone({ Future<Either<AuthFailure, CheckPhone>> checkPhone({
@@ -105,6 +107,9 @@ class AuthRepository implements IAuthRepository {
final auth = result.data!.toDomain(); final auth = result.data!.toDomain();
await _localDataProvider.saveToken(auth.accessToken);
await _localDataProvider.saveCurrentUser(result.data!.data!.user!);
return right(auth); return right(auth);
} catch (e, s) { } catch (e, s) {
log('setPasswordError', name: _logName, error: e, stackTrace: s); log('setPasswordError', name: _logName, error: e, stackTrace: s);
@@ -129,6 +134,9 @@ class AuthRepository implements IAuthRepository {
final auth = result.data!.toDomain(); final auth = result.data!.toDomain();
await _localDataProvider.saveToken(auth.accessToken);
await _localDataProvider.saveCurrentUser(result.data!.data!.user!);
return right(auth); return right(auth);
} catch (e, s) { } catch (e, s) {
log('loginError', name: _logName, error: e, stackTrace: s); log('loginError', name: _logName, error: e, stackTrace: s);
@@ -159,4 +167,31 @@ class AuthRepository implements IAuthRepository {
return left(const AuthFailure.unexpectedError()); return left(const AuthFailure.unexpectedError());
} }
} }
@override
Future<Either<AuthFailure, User>> currentUser() async {
try {
User user = await _localDataProvider.currentUser();
return right(user);
} catch (e, s) {
log('currentUserError', name: _logName, error: e, stackTrace: s);
return left(const AuthFailure.unexpectedError());
}
}
@override
Future<bool> hasToken() async {
return await _localDataProvider.hasToken();
}
@override
Future<Either<AuthFailure, Unit>> logout() async {
try {
await _localDataProvider.deleteAllAuth();
return right(unit);
} catch (e, s) {
log('logoutError', name: _logName, error: e, stackTrace: s);
return left(const AuthFailure.unexpectedError());
}
}
} }
@@ -0,0 +1,8 @@
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_point_dto.dart';
@@ -0,0 +1,443 @@
// 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>(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',
);
CustomerPointDto _$CustomerPointDtoFromJson(Map<String, dynamic> json) {
return _CustomerPointDto.fromJson(json);
}
/// @nodoc
mixin _$CustomerPointDto {
@JsonKey(name: 'status')
String? get status => throw _privateConstructorUsedError;
@JsonKey(name: 'message')
String? get message => throw _privateConstructorUsedError;
@JsonKey(name: 'data')
CustomerPointDataDto? get data => throw _privateConstructorUsedError;
/// Serializes this CustomerPointDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of CustomerPointDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CustomerPointDtoCopyWith<CustomerPointDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CustomerPointDtoCopyWith<$Res> {
factory $CustomerPointDtoCopyWith(
CustomerPointDto value,
$Res Function(CustomerPointDto) then,
) = _$CustomerPointDtoCopyWithImpl<$Res, CustomerPointDto>;
@useResult
$Res call({
@JsonKey(name: 'status') String? status,
@JsonKey(name: 'message') String? message,
@JsonKey(name: 'data') CustomerPointDataDto? data,
});
$CustomerPointDataDtoCopyWith<$Res>? get data;
}
/// @nodoc
class _$CustomerPointDtoCopyWithImpl<$Res, $Val extends CustomerPointDto>
implements $CustomerPointDtoCopyWith<$Res> {
_$CustomerPointDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CustomerPointDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? status = freezed,
Object? message = freezed,
Object? data = freezed,
}) {
return _then(
_value.copyWith(
status: freezed == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String?,
message: freezed == message
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String?,
data: freezed == data
? _value.data
: data // ignore: cast_nullable_to_non_nullable
as CustomerPointDataDto?,
)
as $Val,
);
}
/// Create a copy of CustomerPointDto
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CustomerPointDataDtoCopyWith<$Res>? get data {
if (_value.data == null) {
return null;
}
return $CustomerPointDataDtoCopyWith<$Res>(_value.data!, (value) {
return _then(_value.copyWith(data: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$CustomerPointDtoImplCopyWith<$Res>
implements $CustomerPointDtoCopyWith<$Res> {
factory _$$CustomerPointDtoImplCopyWith(
_$CustomerPointDtoImpl value,
$Res Function(_$CustomerPointDtoImpl) then,
) = __$$CustomerPointDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'status') String? status,
@JsonKey(name: 'message') String? message,
@JsonKey(name: 'data') CustomerPointDataDto? data,
});
@override
$CustomerPointDataDtoCopyWith<$Res>? get data;
}
/// @nodoc
class __$$CustomerPointDtoImplCopyWithImpl<$Res>
extends _$CustomerPointDtoCopyWithImpl<$Res, _$CustomerPointDtoImpl>
implements _$$CustomerPointDtoImplCopyWith<$Res> {
__$$CustomerPointDtoImplCopyWithImpl(
_$CustomerPointDtoImpl _value,
$Res Function(_$CustomerPointDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of CustomerPointDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? status = freezed,
Object? message = freezed,
Object? data = freezed,
}) {
return _then(
_$CustomerPointDtoImpl(
status: freezed == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String?,
message: freezed == message
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String?,
data: freezed == data
? _value.data
: data // ignore: cast_nullable_to_non_nullable
as CustomerPointDataDto?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$CustomerPointDtoImpl extends _CustomerPointDto {
const _$CustomerPointDtoImpl({
@JsonKey(name: 'status') this.status,
@JsonKey(name: 'message') this.message,
@JsonKey(name: 'data') this.data,
}) : super._();
factory _$CustomerPointDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$CustomerPointDtoImplFromJson(json);
@override
@JsonKey(name: 'status')
final String? status;
@override
@JsonKey(name: 'message')
final String? message;
@override
@JsonKey(name: 'data')
final CustomerPointDataDto? data;
@override
String toString() {
return 'CustomerPointDto(status: $status, message: $message, data: $data)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CustomerPointDtoImpl &&
(identical(other.status, status) || other.status == status) &&
(identical(other.message, message) || other.message == message) &&
(identical(other.data, data) || other.data == data));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, status, message, data);
/// Create a copy of CustomerPointDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CustomerPointDtoImplCopyWith<_$CustomerPointDtoImpl> get copyWith =>
__$$CustomerPointDtoImplCopyWithImpl<_$CustomerPointDtoImpl>(
this,
_$identity,
);
@override
Map<String, dynamic> toJson() {
return _$$CustomerPointDtoImplToJson(this);
}
}
abstract class _CustomerPointDto extends CustomerPointDto {
const factory _CustomerPointDto({
@JsonKey(name: 'status') final String? status,
@JsonKey(name: 'message') final String? message,
@JsonKey(name: 'data') final CustomerPointDataDto? data,
}) = _$CustomerPointDtoImpl;
const _CustomerPointDto._() : super._();
factory _CustomerPointDto.fromJson(Map<String, dynamic> json) =
_$CustomerPointDtoImpl.fromJson;
@override
@JsonKey(name: 'status')
String? get status;
@override
@JsonKey(name: 'message')
String? get message;
@override
@JsonKey(name: 'data')
CustomerPointDataDto? get data;
/// Create a copy of CustomerPointDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CustomerPointDtoImplCopyWith<_$CustomerPointDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}
CustomerPointDataDto _$CustomerPointDataDtoFromJson(Map<String, dynamic> json) {
return _CustomerPointDataDto.fromJson(json);
}
/// @nodoc
mixin _$CustomerPointDataDto {
@JsonKey(name: 'total_points')
int? get totalPoints => throw _privateConstructorUsedError;
@JsonKey(name: 'last_updated')
String? get lastUpdated => throw _privateConstructorUsedError;
/// Serializes this CustomerPointDataDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of CustomerPointDataDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CustomerPointDataDtoCopyWith<CustomerPointDataDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CustomerPointDataDtoCopyWith<$Res> {
factory $CustomerPointDataDtoCopyWith(
CustomerPointDataDto value,
$Res Function(CustomerPointDataDto) then,
) = _$CustomerPointDataDtoCopyWithImpl<$Res, CustomerPointDataDto>;
@useResult
$Res call({
@JsonKey(name: 'total_points') int? totalPoints,
@JsonKey(name: 'last_updated') String? lastUpdated,
});
}
/// @nodoc
class _$CustomerPointDataDtoCopyWithImpl<
$Res,
$Val extends CustomerPointDataDto
>
implements $CustomerPointDataDtoCopyWith<$Res> {
_$CustomerPointDataDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CustomerPointDataDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? totalPoints = freezed, Object? lastUpdated = freezed}) {
return _then(
_value.copyWith(
totalPoints: freezed == totalPoints
? _value.totalPoints
: totalPoints // ignore: cast_nullable_to_non_nullable
as int?,
lastUpdated: freezed == lastUpdated
? _value.lastUpdated
: lastUpdated // ignore: cast_nullable_to_non_nullable
as String?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$CustomerPointDataDtoImplCopyWith<$Res>
implements $CustomerPointDataDtoCopyWith<$Res> {
factory _$$CustomerPointDataDtoImplCopyWith(
_$CustomerPointDataDtoImpl value,
$Res Function(_$CustomerPointDataDtoImpl) then,
) = __$$CustomerPointDataDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'total_points') int? totalPoints,
@JsonKey(name: 'last_updated') String? lastUpdated,
});
}
/// @nodoc
class __$$CustomerPointDataDtoImplCopyWithImpl<$Res>
extends _$CustomerPointDataDtoCopyWithImpl<$Res, _$CustomerPointDataDtoImpl>
implements _$$CustomerPointDataDtoImplCopyWith<$Res> {
__$$CustomerPointDataDtoImplCopyWithImpl(
_$CustomerPointDataDtoImpl _value,
$Res Function(_$CustomerPointDataDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of CustomerPointDataDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? totalPoints = freezed, Object? lastUpdated = freezed}) {
return _then(
_$CustomerPointDataDtoImpl(
totalPoints: freezed == totalPoints
? _value.totalPoints
: totalPoints // ignore: cast_nullable_to_non_nullable
as int?,
lastUpdated: freezed == lastUpdated
? _value.lastUpdated
: lastUpdated // ignore: cast_nullable_to_non_nullable
as String?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$CustomerPointDataDtoImpl implements _CustomerPointDataDto {
const _$CustomerPointDataDtoImpl({
@JsonKey(name: 'total_points') this.totalPoints,
@JsonKey(name: 'last_updated') this.lastUpdated,
});
factory _$CustomerPointDataDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$CustomerPointDataDtoImplFromJson(json);
@override
@JsonKey(name: 'total_points')
final int? totalPoints;
@override
@JsonKey(name: 'last_updated')
final String? lastUpdated;
@override
String toString() {
return 'CustomerPointDataDto(totalPoints: $totalPoints, lastUpdated: $lastUpdated)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CustomerPointDataDtoImpl &&
(identical(other.totalPoints, totalPoints) ||
other.totalPoints == totalPoints) &&
(identical(other.lastUpdated, lastUpdated) ||
other.lastUpdated == lastUpdated));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, totalPoints, lastUpdated);
/// Create a copy of CustomerPointDataDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$CustomerPointDataDtoImplCopyWith<_$CustomerPointDataDtoImpl>
get copyWith =>
__$$CustomerPointDataDtoImplCopyWithImpl<_$CustomerPointDataDtoImpl>(
this,
_$identity,
);
@override
Map<String, dynamic> toJson() {
return _$$CustomerPointDataDtoImplToJson(this);
}
}
abstract class _CustomerPointDataDto implements CustomerPointDataDto {
const factory _CustomerPointDataDto({
@JsonKey(name: 'total_points') final int? totalPoints,
@JsonKey(name: 'last_updated') final String? lastUpdated,
}) = _$CustomerPointDataDtoImpl;
factory _CustomerPointDataDto.fromJson(Map<String, dynamic> json) =
_$CustomerPointDataDtoImpl.fromJson;
@override
@JsonKey(name: 'total_points')
int? get totalPoints;
@override
@JsonKey(name: 'last_updated')
String? get lastUpdated;
/// Create a copy of CustomerPointDataDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$CustomerPointDataDtoImplCopyWith<_$CustomerPointDataDtoImpl>
get copyWith => throw _privateConstructorUsedError;
}
@@ -0,0 +1,39 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'customer_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$CustomerPointDtoImpl _$$CustomerPointDtoImplFromJson(
Map<String, dynamic> json,
) => _$CustomerPointDtoImpl(
status: json['status'] as String?,
message: json['message'] as String?,
data: json['data'] == null
? null
: CustomerPointDataDto.fromJson(json['data'] as Map<String, dynamic>),
);
Map<String, dynamic> _$$CustomerPointDtoImplToJson(
_$CustomerPointDtoImpl instance,
) => <String, dynamic>{
'status': instance.status,
'message': instance.message,
'data': instance.data,
};
_$CustomerPointDataDtoImpl _$$CustomerPointDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$CustomerPointDataDtoImpl(
totalPoints: (json['total_points'] as num?)?.toInt(),
lastUpdated: json['last_updated'] as String?,
);
Map<String, dynamic> _$$CustomerPointDataDtoImplToJson(
_$CustomerPointDataDtoImpl instance,
) => <String, dynamic>{
'total_points': instance.totalPoints,
'last_updated': instance.lastUpdated,
};
@@ -0,0 +1,50 @@
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 String _logName = "CustomerRemoteDataProvider";
CustomerRemoteDataProvider(this._apiClient);
Future<DC<CustomerFailure, CustomerPointDto>> fetchCustomerPoint() async {
try {
final response = await _apiClient.get(
ApiPath.customerPoint,
headers: getAuthorizationHeader(),
);
if (response.data['code'] == 401) {
return DC.error(
CustomerFailure.serverError(
ApiFailure.unauthorized('Session Expired'),
),
);
}
if (response.data['status'] == false) {
return DC.error(
CustomerFailure.dynamicErrorMessage(
'Terjadi kesalahan coba lagi nanti',
),
);
}
final dto = CustomerPointDto.fromJson(response.data['data']);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchCustomerPoint', name: _logName, error: e, stackTrace: s);
return DC.error(CustomerFailure.serverError(e));
}
}
}
@@ -0,0 +1,34 @@
part of '../customer_dtos.dart';
@freezed
class CustomerPointDto with _$CustomerPointDto {
const factory CustomerPointDto({
@JsonKey(name: 'status') String? status,
@JsonKey(name: 'message') String? message,
@JsonKey(name: 'data') CustomerPointDataDto? data,
}) = _CustomerPointDto;
factory CustomerPointDto.fromJson(Map<String, dynamic> json) =>
_$CustomerPointDtoFromJson(json);
const CustomerPointDto._();
/// mapping ke domain
CustomerPoint toDomain() => CustomerPoint(
status: status ?? '',
message: message ?? '',
totalPoints: data?.totalPoints ?? 0,
lastUpdated: data?.lastUpdated ?? '',
);
}
@freezed
class CustomerPointDataDto with _$CustomerPointDataDto {
const factory CustomerPointDataDto({
@JsonKey(name: 'total_points') int? totalPoints,
@JsonKey(name: 'last_updated') String? lastUpdated,
}) = _CustomerPointDataDto;
factory CustomerPointDataDto.fromJson(Map<String, dynamic> json) =>
_$CustomerPointDataDtoFromJson(json);
}
@@ -0,0 +1,33 @@
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 String _logName = 'CustomerRepository';
CustomerRepository(this._remoteDataProvider);
@override
Future<Either<CustomerFailure, CustomerPoint>> getPoints() async {
try {
final result = await _remoteDataProvider.fetchCustomerPoint();
if (result.hasError) {
return left(result.error!);
}
final data = result.data!.toDomain();
return right(data);
} catch (e, s) {
log('getPoints', name: _logName, error: e, stackTrace: s);
return left(const CustomerFailure.unexpectedError());
}
}
}
@@ -0,0 +1,47 @@
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/game/game.dart';
import '../game_dtos.dart';
@injectable
class GameRemoteDataProvider {
final ApiClient _apiClient;
final String _logName = "GameRemoteDataProvider";
GameRemoteDataProvider(this._apiClient);
Future<DC<GameFailure, GameDto>> ferrisWheel() async {
try {
final response = await _apiClient.get(
ApiPath.ferrisWheel,
headers: getAuthorizationHeader(),
);
if (response.data['code'] == 401) {
return DC.error(
GameFailure.serverError(ApiFailure.unauthorized('Session Expired')),
);
}
if (response.data['status'] == false) {
return DC.error(
GameFailure.dynamicErrorMessage('Terjadi kesalahan coba lagi nanti'),
);
}
final dto = GameDto.fromJson(response.data['data']['data']['game']);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('ferrisWheel', name: _logName, error: e, stackTrace: s);
return DC.error(GameFailure.serverError(e));
}
}
}
+31
View File
@@ -0,0 +1,31 @@
part of '../game_dtos.dart';
@freezed
class GameDto with _$GameDto {
const factory GameDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'type') String? type,
@JsonKey(name: 'is_active') bool? isActive,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'prizes') List<GamePrizeDto>? prizes,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
}) = _GameDto;
factory GameDto.fromJson(Map<String, dynamic> json) =>
_$GameDtoFromJson(json);
const GameDto._();
Game toDomain() => Game(
id: id ?? '',
name: name ?? '',
type: type ?? '',
isActive: isActive ?? false,
metadata: metadata ?? {},
prizes: prizes?.map((e) => e.toDomain()).toList() ?? [],
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
);
}
@@ -0,0 +1,27 @@
part of '../game_dtos.dart';
@freezed
class GamePrizeDto with _$GamePrizeDto {
const factory GamePrizeDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'game_id') String? gameId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
}) = _GamePrizeDto;
factory GamePrizeDto.fromJson(Map<String, dynamic> json) =>
_$GamePrizeDtoFromJson(json);
const GamePrizeDto._();
GamePrize toDomain() => GamePrize(
id: id ?? '',
gameId: gameId ?? '',
name: name ?? '',
metadata: metadata ?? {},
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
);
}
+9
View File
@@ -0,0 +1,9 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/game/game.dart';
part 'game_dtos.freezed.dart';
part 'game_dtos.g.dart';
part 'dto/game_dto.dart';
part 'dto/game_prize_dto.dart';
@@ -0,0 +1,671 @@
// 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 'game_dtos.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
GameDto _$GameDtoFromJson(Map<String, dynamic> json) {
return _GameDto.fromJson(json);
}
/// @nodoc
mixin _$GameDto {
@JsonKey(name: 'id')
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: 'name')
String? get name => throw _privateConstructorUsedError;
@JsonKey(name: 'type')
String? get type => throw _privateConstructorUsedError;
@JsonKey(name: 'is_active')
bool? get isActive => throw _privateConstructorUsedError;
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
@JsonKey(name: 'prizes')
List<GamePrizeDto>? get prizes => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
String? get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: 'updated_at')
String? get updatedAt => throw _privateConstructorUsedError;
/// Serializes this GameDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of GameDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$GameDtoCopyWith<GameDto> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $GameDtoCopyWith<$Res> {
factory $GameDtoCopyWith(GameDto value, $Res Function(GameDto) then) =
_$GameDtoCopyWithImpl<$Res, GameDto>;
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'type') String? type,
@JsonKey(name: 'is_active') bool? isActive,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'prizes') List<GamePrizeDto>? prizes,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
});
}
/// @nodoc
class _$GameDtoCopyWithImpl<$Res, $Val extends GameDto>
implements $GameDtoCopyWith<$Res> {
_$GameDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of GameDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? name = freezed,
Object? type = freezed,
Object? isActive = freezed,
Object? metadata = freezed,
Object? prizes = 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?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
type: freezed == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String?,
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<String, dynamic>?,
prizes: freezed == prizes
? _value.prizes
: prizes // ignore: cast_nullable_to_non_nullable
as List<GamePrizeDto>?,
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 _$$GameDtoImplCopyWith<$Res> implements $GameDtoCopyWith<$Res> {
factory _$$GameDtoImplCopyWith(
_$GameDtoImpl value,
$Res Function(_$GameDtoImpl) then,
) = __$$GameDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'type') String? type,
@JsonKey(name: 'is_active') bool? isActive,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'prizes') List<GamePrizeDto>? prizes,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
});
}
/// @nodoc
class __$$GameDtoImplCopyWithImpl<$Res>
extends _$GameDtoCopyWithImpl<$Res, _$GameDtoImpl>
implements _$$GameDtoImplCopyWith<$Res> {
__$$GameDtoImplCopyWithImpl(
_$GameDtoImpl _value,
$Res Function(_$GameDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of GameDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? name = freezed,
Object? type = freezed,
Object? isActive = freezed,
Object? metadata = freezed,
Object? prizes = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$GameDtoImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
type: freezed == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String?,
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<String, dynamic>?,
prizes: freezed == prizes
? _value._prizes
: prizes // ignore: cast_nullable_to_non_nullable
as List<GamePrizeDto>?,
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 _$GameDtoImpl extends _GameDto {
const _$GameDtoImpl({
@JsonKey(name: 'id') this.id,
@JsonKey(name: 'name') this.name,
@JsonKey(name: 'type') this.type,
@JsonKey(name: 'is_active') this.isActive,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'prizes') final List<GamePrizeDto>? prizes,
@JsonKey(name: 'created_at') this.createdAt,
@JsonKey(name: 'updated_at') this.updatedAt,
}) : _metadata = metadata,
_prizes = prizes,
super._();
factory _$GameDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$GameDtoImplFromJson(json);
@override
@JsonKey(name: 'id')
final String? id;
@override
@JsonKey(name: 'name')
final String? name;
@override
@JsonKey(name: 'type')
final String? type;
@override
@JsonKey(name: 'is_active')
final bool? isActive;
final Map<String, dynamic>? _metadata;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata {
final value = _metadata;
if (value == null) return null;
if (_metadata is EqualUnmodifiableMapView) return _metadata;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
final List<GamePrizeDto>? _prizes;
@override
@JsonKey(name: 'prizes')
List<GamePrizeDto>? get prizes {
final value = _prizes;
if (value == null) return null;
if (_prizes is EqualUnmodifiableListView) return _prizes;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override
@JsonKey(name: 'created_at')
final String? createdAt;
@override
@JsonKey(name: 'updated_at')
final String? updatedAt;
@override
String toString() {
return 'GameDto(id: $id, name: $name, type: $type, isActive: $isActive, metadata: $metadata, prizes: $prizes, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$GameDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.type, type) || other.type == type) &&
(identical(other.isActive, isActive) ||
other.isActive == isActive) &&
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
const DeepCollectionEquality().equals(other._prizes, _prizes) &&
(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,
name,
type,
isActive,
const DeepCollectionEquality().hash(_metadata),
const DeepCollectionEquality().hash(_prizes),
createdAt,
updatedAt,
);
/// Create a copy of GameDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$GameDtoImplCopyWith<_$GameDtoImpl> get copyWith =>
__$$GameDtoImplCopyWithImpl<_$GameDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$GameDtoImplToJson(this);
}
}
abstract class _GameDto extends GameDto {
const factory _GameDto({
@JsonKey(name: 'id') final String? id,
@JsonKey(name: 'name') final String? name,
@JsonKey(name: 'type') final String? type,
@JsonKey(name: 'is_active') final bool? isActive,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'prizes') final List<GamePrizeDto>? prizes,
@JsonKey(name: 'created_at') final String? createdAt,
@JsonKey(name: 'updated_at') final String? updatedAt,
}) = _$GameDtoImpl;
const _GameDto._() : super._();
factory _GameDto.fromJson(Map<String, dynamic> json) = _$GameDtoImpl.fromJson;
@override
@JsonKey(name: 'id')
String? get id;
@override
@JsonKey(name: 'name')
String? get name;
@override
@JsonKey(name: 'type')
String? get type;
@override
@JsonKey(name: 'is_active')
bool? get isActive;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata;
@override
@JsonKey(name: 'prizes')
List<GamePrizeDto>? get prizes;
@override
@JsonKey(name: 'created_at')
String? get createdAt;
@override
@JsonKey(name: 'updated_at')
String? get updatedAt;
/// Create a copy of GameDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$GameDtoImplCopyWith<_$GameDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}
GamePrizeDto _$GamePrizeDtoFromJson(Map<String, dynamic> json) {
return _GamePrizeDto.fromJson(json);
}
/// @nodoc
mixin _$GamePrizeDto {
@JsonKey(name: 'id')
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: 'game_id')
String? get gameId => throw _privateConstructorUsedError;
@JsonKey(name: 'name')
String? get name => throw _privateConstructorUsedError;
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
String? get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: 'updated_at')
String? get updatedAt => throw _privateConstructorUsedError;
/// Serializes this GamePrizeDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of GamePrizeDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$GamePrizeDtoCopyWith<GamePrizeDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $GamePrizeDtoCopyWith<$Res> {
factory $GamePrizeDtoCopyWith(
GamePrizeDto value,
$Res Function(GamePrizeDto) then,
) = _$GamePrizeDtoCopyWithImpl<$Res, GamePrizeDto>;
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'game_id') String? gameId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
});
}
/// @nodoc
class _$GamePrizeDtoCopyWithImpl<$Res, $Val extends GamePrizeDto>
implements $GamePrizeDtoCopyWith<$Res> {
_$GamePrizeDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of GamePrizeDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? gameId = freezed,
Object? name = 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?,
gameId: freezed == gameId
? _value.gameId
: gameId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
metadata: freezed == metadata
? _value.metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as String?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as String?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$GamePrizeDtoImplCopyWith<$Res>
implements $GamePrizeDtoCopyWith<$Res> {
factory _$$GamePrizeDtoImplCopyWith(
_$GamePrizeDtoImpl value,
$Res Function(_$GamePrizeDtoImpl) then,
) = __$$GamePrizeDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'game_id') String? gameId,
@JsonKey(name: 'name') String? name,
@JsonKey(name: 'metadata') Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') String? createdAt,
@JsonKey(name: 'updated_at') String? updatedAt,
});
}
/// @nodoc
class __$$GamePrizeDtoImplCopyWithImpl<$Res>
extends _$GamePrizeDtoCopyWithImpl<$Res, _$GamePrizeDtoImpl>
implements _$$GamePrizeDtoImplCopyWith<$Res> {
__$$GamePrizeDtoImplCopyWithImpl(
_$GamePrizeDtoImpl _value,
$Res Function(_$GamePrizeDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of GamePrizeDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? gameId = freezed,
Object? name = freezed,
Object? metadata = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$GamePrizeDtoImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
gameId: freezed == gameId
? _value.gameId
: gameId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
metadata: freezed == metadata
? _value._metadata
: metadata // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as String?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as String?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$GamePrizeDtoImpl extends _GamePrizeDto {
const _$GamePrizeDtoImpl({
@JsonKey(name: 'id') this.id,
@JsonKey(name: 'game_id') this.gameId,
@JsonKey(name: 'name') this.name,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') this.createdAt,
@JsonKey(name: 'updated_at') this.updatedAt,
}) : _metadata = metadata,
super._();
factory _$GamePrizeDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$GamePrizeDtoImplFromJson(json);
@override
@JsonKey(name: 'id')
final String? id;
@override
@JsonKey(name: 'game_id')
final String? gameId;
@override
@JsonKey(name: 'name')
final String? name;
final Map<String, dynamic>? _metadata;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata {
final value = _metadata;
if (value == null) return null;
if (_metadata is EqualUnmodifiableMapView) return _metadata;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
@override
@JsonKey(name: 'created_at')
final String? createdAt;
@override
@JsonKey(name: 'updated_at')
final String? updatedAt;
@override
String toString() {
return 'GamePrizeDto(id: $id, gameId: $gameId, name: $name, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$GamePrizeDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.gameId, gameId) || other.gameId == gameId) &&
(identical(other.name, name) || other.name == name) &&
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,
gameId,
name,
const DeepCollectionEquality().hash(_metadata),
createdAt,
updatedAt,
);
/// Create a copy of GamePrizeDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$GamePrizeDtoImplCopyWith<_$GamePrizeDtoImpl> get copyWith =>
__$$GamePrizeDtoImplCopyWithImpl<_$GamePrizeDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$GamePrizeDtoImplToJson(this);
}
}
abstract class _GamePrizeDto extends GamePrizeDto {
const factory _GamePrizeDto({
@JsonKey(name: 'id') final String? id,
@JsonKey(name: 'game_id') final String? gameId,
@JsonKey(name: 'name') final String? name,
@JsonKey(name: 'metadata') final Map<String, dynamic>? metadata,
@JsonKey(name: 'created_at') final String? createdAt,
@JsonKey(name: 'updated_at') final String? updatedAt,
}) = _$GamePrizeDtoImpl;
const _GamePrizeDto._() : super._();
factory _GamePrizeDto.fromJson(Map<String, dynamic> json) =
_$GamePrizeDtoImpl.fromJson;
@override
@JsonKey(name: 'id')
String? get id;
@override
@JsonKey(name: 'game_id')
String? get gameId;
@override
@JsonKey(name: 'name')
String? get name;
@override
@JsonKey(name: 'metadata')
Map<String, dynamic>? get metadata;
@override
@JsonKey(name: 'created_at')
String? get createdAt;
@override
@JsonKey(name: 'updated_at')
String? get updatedAt;
/// Create a copy of GamePrizeDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$GamePrizeDtoImplCopyWith<_$GamePrizeDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}
+53
View File
@@ -0,0 +1,53 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'game_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$GameDtoImpl _$$GameDtoImplFromJson(Map<String, dynamic> json) =>
_$GameDtoImpl(
id: json['id'] as String?,
name: json['name'] as String?,
type: json['type'] as String?,
isActive: json['is_active'] as bool?,
metadata: json['metadata'] as Map<String, dynamic>?,
prizes: (json['prizes'] as List<dynamic>?)
?.map((e) => GamePrizeDto.fromJson(e as Map<String, dynamic>))
.toList(),
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$GameDtoImplToJson(_$GameDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'name': instance.name,
'type': instance.type,
'is_active': instance.isActive,
'metadata': instance.metadata,
'prizes': instance.prizes,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
_$GamePrizeDtoImpl _$$GamePrizeDtoImplFromJson(Map<String, dynamic> json) =>
_$GamePrizeDtoImpl(
id: json['id'] as String?,
gameId: json['game_id'] as String?,
name: json['name'] as String?,
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$GamePrizeDtoImplToJson(_$GamePrizeDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'game_id': instance.gameId,
'name': instance.name,
'metadata': instance.metadata,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
@@ -0,0 +1,34 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/game/game.dart';
import '../datasources/remote_data_provider.dart';
@Injectable(as: IGameRepository)
class GameRepository implements IGameRepository {
final GameRemoteDataProvider _remoteDataProvider;
final String _logName = 'GameRepository';
GameRepository(this._remoteDataProvider);
@override
Future<Either<GameFailure, Game>> ferrisWheel() async {
try {
final result = await _remoteDataProvider.ferrisWheel();
if (result.hasError) {
return left(result.error!);
}
final data = result.data!.toDomain();
return right(data);
} catch (e, s) {
log('ferrisWheel', name: _logName, error: e, stackTrace: s);
return left(const GameFailure.unexpectedError());
}
}
}
+63 -14
View File
@@ -11,10 +11,13 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes // ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:connectivity_plus/connectivity_plus.dart' as _i895; import 'package:connectivity_plus/connectivity_plus.dart' as _i895;
import 'package:dio/dio.dart' as _i361; import 'package:dio/dio.dart' as _i361;
import 'package:enaklo/application/auth/auth_bloc.dart' as _i771;
import 'package:enaklo/application/auth/check_phone_form/check_phone_form_bloc.dart' import 'package:enaklo/application/auth/check_phone_form/check_phone_form_bloc.dart'
as _i869; as _i869;
import 'package:enaklo/application/auth/login_form/login_form_bloc.dart' import 'package:enaklo/application/auth/login_form/login_form_bloc.dart'
as _i510; as _i510;
import 'package:enaklo/application/auth/logout_form/logout_form_bloc.dart'
as _i216;
import 'package:enaklo/application/auth/register_form/register_form_bloc.dart' import 'package:enaklo/application/auth/register_form/register_form_bloc.dart'
as _i260; as _i260;
import 'package:enaklo/application/auth/resend_form/resend_form_bloc.dart' import 'package:enaklo/application/auth/resend_form/resend_form_bloc.dart'
@@ -23,6 +26,10 @@ import 'package:enaklo/application/auth/set_password/set_password_form_bloc.dart
as _i174; as _i174;
import 'package:enaklo/application/auth/verify_form/verify_form_bloc.dart' import 'package:enaklo/application/auth/verify_form/verify_form_bloc.dart'
as _i521; as _i521;
import 'package:enaklo/application/customer/customer_point_loader/customer_point_loader_bloc.dart'
as _i497;
import 'package:enaklo/application/game/ferris_wheel_loader/ferris_wheel_loader_bloc.dart'
as _i1013;
import 'package:enaklo/common/api/api_client.dart' as _i842; import 'package:enaklo/common/api/api_client.dart' as _i842;
import 'package:enaklo/common/di/di_auto_route.dart' as _i619; import 'package:enaklo/common/di/di_auto_route.dart' as _i619;
import 'package:enaklo/common/di/di_connectivity.dart' as _i644; import 'package:enaklo/common/di/di_connectivity.dart' as _i644;
@@ -30,11 +37,23 @@ import 'package:enaklo/common/di/di_dio.dart' as _i842;
import 'package:enaklo/common/di/di_shared_preferences.dart' as _i672; import 'package:enaklo/common/di/di_shared_preferences.dart' as _i672;
import 'package:enaklo/common/network/network_client.dart' as _i109; import 'package:enaklo/common/network/network_client.dart' as _i109;
import 'package:enaklo/domain/auth/auth.dart' as _i995; import 'package:enaklo/domain/auth/auth.dart' as _i995;
import 'package:enaklo/domain/customer/customer.dart' as _i898;
import 'package:enaklo/domain/game/game.dart' as _i96;
import 'package:enaklo/env.dart' as _i372; import 'package:enaklo/env.dart' as _i372;
import 'package:enaklo/infrastructure/auth/datasources/local_data_provider.dart'
as _i1003;
import 'package:enaklo/infrastructure/auth/datasources/remote_data_provider.dart' import 'package:enaklo/infrastructure/auth/datasources/remote_data_provider.dart'
as _i818; as _i818;
import 'package:enaklo/infrastructure/auth/repositories/auth_repository.dart' import 'package:enaklo/infrastructure/auth/repositories/auth_repository.dart'
as _i879; as _i879;
import 'package:enaklo/infrastructure/customer/datasources/remote_data_provider.dart'
as _i89;
import 'package:enaklo/infrastructure/customer/repositories/customer_repository.dart'
as _i118;
import 'package:enaklo/infrastructure/game/datasources/remote_data_provider.dart'
as _i143;
import 'package:enaklo/infrastructure/game/repositories/game_repository.dart'
as _i547;
import 'package:enaklo/presentation/router/app_router.dart' as _i698; import 'package:enaklo/presentation/router/app_router.dart' as _i698;
import 'package:get_it/get_it.dart' as _i174; import 'package:get_it/get_it.dart' as _i174;
import 'package:injectable/injectable.dart' as _i526; import 'package:injectable/injectable.dart' as _i526;
@@ -65,6 +84,9 @@ extension GetItInjectableX on _i174.GetIt {
() => _i109.NetworkClient(gh<_i895.Connectivity>()), () => _i109.NetworkClient(gh<_i895.Connectivity>()),
); );
gh.factory<_i372.Env>(() => _i372.DevEnv(), registerFor: {_dev}); gh.factory<_i372.Env>(() => _i372.DevEnv(), registerFor: {_dev});
gh.factory<_i1003.AuthLocalDataProvider>(
() => _i1003.AuthLocalDataProvider(gh<_i460.SharedPreferences>()),
);
gh.factory<_i372.Env>(() => _i372.ProdEnv(), registerFor: {_prod}); gh.factory<_i372.Env>(() => _i372.ProdEnv(), registerFor: {_prod});
gh.lazySingleton<_i842.ApiClient>( gh.lazySingleton<_i842.ApiClient>(
() => _i842.ApiClient(gh<_i361.Dio>(), gh<_i372.Env>()), () => _i842.ApiClient(gh<_i361.Dio>(), gh<_i372.Env>()),
@@ -72,26 +94,53 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i818.AuthRemoteDataProvider>( gh.factory<_i818.AuthRemoteDataProvider>(
() => _i818.AuthRemoteDataProvider(gh<_i842.ApiClient>()), () => _i818.AuthRemoteDataProvider(gh<_i842.ApiClient>()),
); );
gh.factory<_i143.GameRemoteDataProvider>(
() => _i143.GameRemoteDataProvider(gh<_i842.ApiClient>()),
);
gh.factory<_i89.CustomerRemoteDataProvider>(
() => _i89.CustomerRemoteDataProvider(gh<_i842.ApiClient>()),
);
gh.factory<_i96.IGameRepository>(
() => _i547.GameRepository(gh<_i143.GameRemoteDataProvider>()),
);
gh.factory<_i1013.FerrisWheelLoaderBloc>(
() => _i1013.FerrisWheelLoaderBloc(gh<_i96.IGameRepository>()),
);
gh.factory<_i995.IAuthRepository>( gh.factory<_i995.IAuthRepository>(
() => _i879.AuthRepository(gh<_i818.AuthRemoteDataProvider>()), () => _i879.AuthRepository(
gh<_i818.AuthRemoteDataProvider>(),
gh<_i1003.AuthLocalDataProvider>(),
),
); );
gh.factory<_i510.LoginFormBloc>( gh.factory<_i627.ResendFormBloc>(
() => _i510.LoginFormBloc(gh<_i995.IAuthRepository>()), () => _i627.ResendFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i869.CheckPhoneFormBloc>(
() => _i869.CheckPhoneFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i260.RegisterFormBloc>(
() => _i260.RegisterFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i521.VerifyFormBloc>(
() => _i521.VerifyFormBloc(gh<_i995.IAuthRepository>()),
); );
gh.factory<_i174.SetPasswordFormBloc>( gh.factory<_i174.SetPasswordFormBloc>(
() => _i174.SetPasswordFormBloc(gh<_i995.IAuthRepository>()), () => _i174.SetPasswordFormBloc(gh<_i995.IAuthRepository>()),
); );
gh.factory<_i627.ResendFormBloc>( gh.factory<_i260.RegisterFormBloc>(
() => _i627.ResendFormBloc(gh<_i995.IAuthRepository>()), () => _i260.RegisterFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i869.CheckPhoneFormBloc>(
() => _i869.CheckPhoneFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i771.AuthBloc>(
() => _i771.AuthBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i521.VerifyFormBloc>(
() => _i521.VerifyFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i216.LogoutFormBloc>(
() => _i216.LogoutFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i898.ICustomerRepository>(
() => _i118.CustomerRepository(gh<_i89.CustomerRemoteDataProvider>()),
);
gh.factory<_i510.LoginFormBloc>(
() => _i510.LoginFormBloc(gh<_i995.IAuthRepository>()),
);
gh.factory<_i497.CustomerPointLoaderBloc>(
() => _i497.CustomerPointLoaderBloc(gh<_i898.ICustomerRepository>()),
); );
return this; return this;
} }
+2
View File
@@ -2,12 +2,14 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'injection.dart'; import 'injection.dart';
import 'presentation/app_widget.dart'; import 'presentation/app_widget.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await initializeDateFormatting('id_ID', null);
SystemChrome.setSystemUIOverlayStyle( SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle( const SystemUiOverlayStyle(
+17 -6
View File
@@ -1,5 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../application/auth/auth_bloc.dart';
import '../application/auth/logout_form/logout_form_bloc.dart';
import '../application/customer/customer_point_loader/customer_point_loader_bloc.dart';
import '../common/theme/theme.dart'; import '../common/theme/theme.dart';
import '../common/constant/app_constant.dart'; import '../common/constant/app_constant.dart';
import '../injection.dart'; import '../injection.dart';
@@ -18,12 +22,19 @@ class _AppWidgetState extends State<AppWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp.router( return MultiBlocProvider(
debugShowCheckedModeBanner: false, providers: [
title: AppConstant.appName, BlocProvider(create: (context) => getIt<AuthBloc>()),
theme: ThemeApp.theme, BlocProvider(create: (context) => getIt<LogoutFormBloc>()),
routerConfig: _appRouter.config( BlocProvider(create: (context) => getIt<CustomerPointLoaderBloc>()),
navigatorObservers: () => <NavigatorObserver>[AppRouteObserver()], ],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
title: AppConstant.appName,
theme: ThemeApp.theme,
routerConfig: _appRouter.config(
navigatorObservers: () => <NavigatorObserver>[AppRouteObserver()],
),
), ),
); );
} }
@@ -11,6 +11,52 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class $AssetsAudioGen {
const $AssetsAudioGen();
/// File path: assets/audio/bell_ding.mp3
String get bellDing => 'assets/audio/bell_ding.mp3';
/// File path: assets/audio/big_win.mp3
String get bigWin => 'assets/audio/big_win.mp3';
/// File path: assets/audio/button_tap.mp3
String get buttonTap => 'assets/audio/button_tap.mp3';
/// File path: assets/audio/carnaval_main_theme.mp3
String get carnavalMainTheme => 'assets/audio/carnaval_main_theme.mp3';
/// File path: assets/audio/token_sound.mp3
String get tokenSound => 'assets/audio/token_sound.mp3';
/// File path: assets/audio/wheel_spin.mp3
String get wheelSpin => 'assets/audio/wheel_spin.mp3';
/// List of all assets
List<String> get values => [
bellDing,
bigWin,
buttonTap,
carnavalMainTheme,
tokenSound,
wheelSpin,
];
}
class $AssetsIconsGen {
const $AssetsIconsGen();
/// File path: assets/icons/dine_in.png
AssetGenImage get dineIn => const AssetGenImage('assets/icons/dine_in.png');
/// File path: assets/icons/takeaway.png
AssetGenImage get takeaway =>
const AssetGenImage('assets/icons/takeaway.png');
/// List of all assets
List<AssetGenImage> get values => [dineIn, takeaway];
}
class $AssetsImagesGen { class $AssetsImagesGen {
const $AssetsImagesGen(); const $AssetsImagesGen();
@@ -64,6 +110,8 @@ class $AssetsImagesGen {
class Assets { class Assets {
const Assets._(); const Assets._();
static const $AssetsAudioGen audio = $AssetsAudioGen();
static const $AssetsIconsGen icons = $AssetsIconsGen();
static const $AssetsImagesGen images = $AssetsImagesGen(); static const $AssetsImagesGen images = $AssetsImagesGen();
} }
@@ -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)),
);
}),
);
},
),
);
}
}
@@ -1,5 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
part 'elevated_button.dart'; part 'elevated_button.dart';
part 'outline_button.dart';
part 'qty_button.dart';
@@ -6,13 +6,15 @@ class AppElevatedButton extends StatelessWidget {
required this.onPressed, required this.onPressed,
required this.title, required this.title,
this.width = double.infinity, this.width = double.infinity,
this.height = 48.0, this.height = 44.0,
this.isLoading = false,
}); });
final Function()? onPressed; final Function()? onPressed;
final String title; final String title;
final double width; final double width;
final double height; final double height;
final bool isLoading;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -21,13 +23,29 @@ class AppElevatedButton extends StatelessWidget {
height: height, height: height,
child: ElevatedButton( child: ElevatedButton(
onPressed: onPressed, onPressed: onPressed,
child: Text( child: isLoading
title, ? Row(
style: AppStyle.lg.copyWith( mainAxisAlignment: MainAxisAlignment.center,
color: AppColor.white, crossAxisAlignment: CrossAxisAlignment.center,
fontWeight: FontWeight.w700, children: [
), SpinKitFadingCircle(color: AppColor.white, size: 24),
), SizedBox(width: 8),
Text(
'Loading',
style: AppStyle.lg.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w700,
),
),
],
)
: Text(
title,
style: AppStyle.md.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w700,
),
),
), ),
); );
} }
@@ -0,0 +1,58 @@
part of 'button.dart';
class AppOutlineButton extends StatelessWidget {
const AppOutlineButton({
super.key,
required this.onPressed,
required this.title,
this.width = double.infinity,
this.height = 44.0,
this.isLoading = false,
this.borderColor,
});
final Function()? onPressed;
final String title;
final double width;
final double height;
final bool isLoading;
final Color? borderColor;
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
height: height,
child: OutlinedButton(
onPressed: onPressed,
style: OutlinedButton.styleFrom(
padding: EdgeInsets.zero,
side: BorderSide(color: borderColor ?? AppColor.primary),
),
child: isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SpinKitFadingCircle(color: AppColor.white, size: 24),
SizedBox(width: 8),
Text(
'Loading',
style: AppStyle.lg.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w700,
),
),
],
)
: Text(
title,
style: AppStyle.md.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w700,
),
),
),
);
}
}
@@ -0,0 +1,38 @@
part of 'button.dart';
class QtyButton extends StatelessWidget {
const QtyButton({super.key});
@override
Widget build(BuildContext context) {
return Row(
children: [
InkWell(
child: Container(
height: 35,
width: 35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(width: 1, color: AppColor.border),
),
child: Icon(Icons.remove),
),
),
SizedBox(width: 12),
Text('1', style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold)),
SizedBox(width: 12),
InkWell(
child: Container(
height: 35,
width: 35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(width: 1, color: AppColor.border),
),
child: Icon(Icons.add),
),
),
],
);
}
}
@@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
class GradientCard extends StatelessWidget {
final Widget child;
final List<Color>? gradientColors;
final double borderRadius;
final EdgeInsetsGeometry? padding;
final bool showDecoration;
const GradientCard({
super.key,
required this.child,
this.gradientColors,
this.borderRadius = 16,
this.padding = const EdgeInsets.all(16.0),
this.showDecoration = true,
});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: gradientColors ?? AppColor.primaryGradient,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(borderRadius),
),
child: Stack(
children: [
// Background Pattern (optional)
if (showDecoration) ..._buildDecorations(),
// Main Content
Padding(padding: padding ?? EdgeInsets.zero, child: child),
],
),
);
}
List<Widget> _buildDecorations() {
return [
// Top Right Circle
Positioned(
top: -20,
right: -20,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withOpacity(0.1),
),
),
),
// Middle Right Circle
Positioned(
top: 30,
right: 20,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withOpacity(0.08),
),
),
),
// Bottom Left Circle
Positioned(
bottom: -10,
left: -10,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withOpacity(0.06),
),
),
),
// Top Left Decorative Line
Positioned(
top: 10,
left: -5,
child: Transform.rotate(
angle: 0.5,
child: Container(
width: 30,
height: 2,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(1),
),
),
),
),
// Bottom Right Decorative Line
Positioned(
bottom: 15,
right: 10,
child: Transform.rotate(
angle: -0.5,
child: Container(
width: 25,
height: 2,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(1),
),
),
),
),
];
}
}
@@ -0,0 +1,153 @@
import 'package:flutter/material.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../sample/product_sample_data.dart';
class ProductCard extends StatelessWidget {
final Product product;
final Function()? onTap;
const ProductCard({super.key, required this.product, this.onTap});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.06),
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Product image
Expanded(
flex: 3,
child: Stack(
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColor.backgroundLight,
borderRadius: BorderRadius.vertical(
top: Radius.circular(12),
),
),
child: Center(
child: Icon(
Icons.fastfood,
size: 40,
color: AppColor.textLight,
),
),
),
// Availability overlay
if (!product.isAvailable)
Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
color: AppColor.black.withOpacity(0.6),
borderRadius: BorderRadius.vertical(
top: Radius.circular(12),
),
),
child: Center(
child: Text(
"HABIS",
style: AppStyle.sm.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
),
),
),
),
// Rating badge
Positioned(
top: 8,
right: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, size: 12, color: AppColor.warning),
SizedBox(width: 2),
Text(
"${product.rating}",
style: AppStyle.xs.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
],
),
),
// Product info
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.name,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Spacer(),
// Price and sold count
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Rp ${product.price.currencyFormatRp}",
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
Text(
"${product.soldCount} terjual",
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
),
),
],
),
],
),
),
),
],
),
),
);
}
}
@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
class ProductEmptyCard extends StatelessWidget {
const ProductEmptyCard({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.borderLight),
),
child: Center(
child: Column(
children: [
Icon(
Icons.inventory_2_outlined,
size: 48,
color: AppColor.textLight,
),
SizedBox(height: 12),
Text(
"Belum ada produk",
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
),
],
),
),
);
}
}
@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import '../../../common/data/service_data.dart';
import '../../../common/theme/theme.dart';
import '../image/image.dart';
import 'gradient_card.dart';
class ServiceCard extends StatelessWidget {
final Service service;
const ServiceCard({super.key, required this.service});
@override
Widget build(BuildContext context) {
return GradientCard(
padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadiusGeometry.circular(8),
child: Image.asset(
service.imagePath,
width: 60,
height: 60,
errorBuilder: (context, error, stackTrace) =>
ImagePlaceholder(width: 60, height: 60),
),
),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
service.name,
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.white,
),
),
Text(
service.description,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.w500,
color: AppColor.white,
),
),
],
),
),
InkWell(
child: Text(
'Ubah',
style: AppStyle.md.copyWith(
color: AppColor.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
}
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
class VariantCard extends StatelessWidget {
final String name;
final bool isSelected;
const VariantCard({super.key, required this.name, this.isSelected = false});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppValue.borderRadius),
color: isSelected ? AppColor.primary.withOpacity(0.1) : AppColor.white,
border: Border.all(
width: isSelected ? 2 : 1,
color: isSelected ? AppColor.primary : AppColor.border,
),
),
child: Row(
children: [
Expanded(
child: Text(
name,
style: AppStyle.md.copyWith(fontWeight: FontWeight.w600),
),
),
SizedBox(width: 12),
Text(
"+${"2000".currencyFormatRp}",
style: AppStyle.md.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w500,
),
),
],
),
);
}
}
@@ -0,0 +1,106 @@
import 'package:flutter/widgets.dart';
import '../../../common/theme/theme.dart';
import '../../../sample/product_sample_data.dart';
class SliverCategoryDelegate extends SliverPersistentHeaderDelegate {
final List<ProductCategory> categories;
final String selectedCategoryId;
final Function(String) onCategoryTap;
SliverCategoryDelegate({
required this.categories,
required this.selectedCategoryId,
required this.onCategoryTap,
});
@override
double get minExtent => 60;
@override
double get maxExtent => 60;
@override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
return Container(
height: 60,
decoration: BoxDecoration(
color: AppColor.surface,
border: Border(
bottom: BorderSide(color: AppColor.borderLight, width: 1),
),
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemCount: categories.length,
itemBuilder: (context, index) {
final category = categories[index];
final isSelected = category.id == selectedCategoryId;
return GestureDetector(
onTap: () => onCategoryTap(category.id),
child: Container(
margin: EdgeInsets.only(right: 12),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? AppColor.primary : AppColor.backgroundLight,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? AppColor.primary : AppColor.border,
width: 1,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(category.icon, style: AppStyle.md),
SizedBox(width: 8),
Text(
category.name,
style: AppStyle.md.copyWith(
color: isSelected
? AppColor.textWhite
: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 4),
Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: isSelected
? AppColor.textWhite.withOpacity(0.2)
: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Text(
"${category.productCount}",
style: AppStyle.xs.copyWith(
color: isSelected
? AppColor.textWhite
: AppColor.primary,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
},
),
);
}
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return oldDelegate is SliverCategoryDelegate &&
(oldDelegate.selectedCategoryId != selectedCategoryId ||
oldDelegate.categories != categories);
}
}
@@ -0,0 +1,59 @@
part of 'field.dart';
class DatePickerField extends StatefulWidget {
final String label;
final DateTime? selectedDate;
final Function(DateTime) onDateSelected;
const DatePickerField({
super.key,
required this.label,
required this.onDateSelected,
this.selectedDate,
});
@override
State<DatePickerField> createState() => _DatePickerFieldState();
}
class _DatePickerFieldState extends State<DatePickerField> {
DateTime? _selectedDate;
@override
void initState() {
super.initState();
_selectedDate = widget.selectedDate;
}
Future<void> _selectDate() async {
final picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2050),
);
if (picked != null && picked != _selectedDate) {
setState(() {
_selectedDate = picked;
});
widget.onDateSelected(picked);
}
}
@override
Widget build(BuildContext context) {
return AppTextFormField(
title: widget.label,
hintText: 'Pilih tanggal',
readOnly: true,
controller: TextEditingController(text: _selectedDate?.toServerDate),
onChanged: (value) {
widget.onDateSelected(_selectedDate!);
},
onTap: () {
_selectDate();
},
);
}
}
@@ -1,7 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
part 'text_form_field.dart'; part 'text_form_field.dart';
part 'search_text_form_field.dart'; part 'search_text_form_field.dart';
part 'password_text_form_page.dart'; part 'password_text_form_page.dart';
part 'date_text_form_field.dart';
@@ -10,6 +10,7 @@ class AppPasswordTextFormField extends StatefulWidget {
this.prefixIcon, this.prefixIcon,
this.keyboardType, this.keyboardType,
this.onChanged, this.onChanged,
this.validator,
}); });
final String? hintText; final String? hintText;
@@ -19,6 +20,7 @@ class AppPasswordTextFormField extends StatefulWidget {
final Widget? prefixIcon; final Widget? prefixIcon;
final TextInputType? keyboardType; final TextInputType? keyboardType;
final ValueChanged<String>? onChanged; final ValueChanged<String>? onChanged;
final String? Function(String?)? validator;
@override @override
State<AppPasswordTextFormField> createState() => State<AppPasswordTextFormField> createState() =>
@@ -26,7 +28,7 @@ class AppPasswordTextFormField extends StatefulWidget {
} }
class _AppPasswordTextFormFieldState extends State<AppPasswordTextFormField> { class _AppPasswordTextFormFieldState extends State<AppPasswordTextFormField> {
bool isPasswordVisible = false; bool isPasswordVisible = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@@ -48,6 +50,7 @@ class _AppPasswordTextFormFieldState extends State<AppPasswordTextFormField> {
color: AppColor.textPrimary, color: AppColor.textPrimary,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
validator: widget.validator,
decoration: InputDecoration( decoration: InputDecoration(
hintText: widget.hintText, hintText: widget.hintText,
prefixIcon: widget.prefixIcon, prefixIcon: widget.prefixIcon,
@@ -11,6 +11,9 @@ class AppTextFormField extends StatelessWidget {
this.suffixIcon, this.suffixIcon,
this.keyboardType, this.keyboardType,
this.onChanged, this.onChanged,
this.validator,
this.readOnly = false,
this.onTap,
}); });
final String? hintText; final String? hintText;
@@ -21,6 +24,9 @@ class AppTextFormField extends StatelessWidget {
final Widget? suffixIcon; final Widget? suffixIcon;
final TextInputType? keyboardType; final TextInputType? keyboardType;
final ValueChanged<String>? onChanged; final ValueChanged<String>? onChanged;
final String? Function(String?)? validator;
final bool readOnly;
final Function()? onTap;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -39,6 +45,9 @@ class AppTextFormField extends StatelessWidget {
color: AppColor.textPrimary, color: AppColor.textPrimary,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
validator: validator,
onTap: onTap,
readOnly: readOnly,
decoration: InputDecoration( decoration: InputDecoration(
hintText: hintText, hintText: hintText,
prefixIcon: prefixIcon, prefixIcon: prefixIcon,
@@ -0,0 +1,54 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/auth/auth.dart';
class AppFlushbar {
static void showSuccess(BuildContext context, String message) {
Flushbar(
messageText: Text(
message,
style: AppStyle.lg.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
icon: const Icon(Icons.check_circle, color: Colors.white),
duration: const Duration(seconds: 2),
flushbarPosition: FlushbarPosition.TOP,
backgroundColor: AppColor.secondary,
borderRadius: BorderRadius.circular(12),
margin: const EdgeInsets.all(12),
).show(context);
}
static void showError(BuildContext context, String message) {
Flushbar(
messageText: Text(
message,
style: AppStyle.lg.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
icon: const Icon(Icons.error, color: Colors.white),
duration: const Duration(seconds: 3),
flushbarPosition: FlushbarPosition.TOP,
backgroundColor: AppColor.error,
borderRadius: BorderRadius.circular(12),
margin: const EdgeInsets.all(12),
).show(context);
}
static void showAuthFailureToast(BuildContext context, AuthFailure failure) =>
showError(
context,
failure.map(
serverError: (value) => value.failure.toStringFormatted(context),
dynamicErrorMessage: (value) => value.erroMessage,
unexpectedError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
),
);
}
@@ -1,50 +1,136 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/auth/auth_bloc.dart';
import '../../../../application/auth/set_password/set_password_form_bloc.dart';
import '../../../../injection.dart';
import '../../../components/button/button.dart'; import '../../../components/button/button.dart';
import '../../../components/field/field.dart'; import '../../../components/field/field.dart';
import '../../../components/toast/flushbar.dart';
import '../../../router/app_router.gr.dart'; import '../../../router/app_router.gr.dart';
@RoutePage() @RoutePage()
class CreatePasswordPage extends StatelessWidget { class CreatePasswordPage extends StatelessWidget implements AutoRouteWrapper {
const CreatePasswordPage({super.key}); final String registrationToken;
const CreatePasswordPage({super.key, required this.registrationToken});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return BlocListener<SetPasswordFormBloc, SetPasswordFormState>(
appBar: AppBar(title: const Text('Buat Kata Sandi')), listenWhen: (p, c) =>
body: Padding( p.failureOrSetPasswordOption != c.failureOrSetPasswordOption,
padding: const EdgeInsets.symmetric(horizontal: 24.0), listener: (context, state) {
child: Column( state.failureOrSetPasswordOption.fold(
crossAxisAlignment: CrossAxisAlignment.start, () => null,
children: [ (either) => either.fold(
const SizedBox(height: 40), (f) => AppFlushbar.showAuthFailureToast(context, f),
(data) {
AppFlushbar.showSuccess(context, data.message);
Future.delayed(Duration(milliseconds: 1000), () {
context.read<AuthBloc>().add(AuthEvent.fetchCurrentUser());
context.router.replaceAll([MainRoute()]);
});
},
),
);
},
child: Scaffold(
appBar: AppBar(title: const Text('Buat Kata Sandi')),
body: BlocBuilder<SetPasswordFormBloc, SetPasswordFormState>(
builder: (context, state) {
return Form(
autovalidateMode: state.showErrorMessages
? AutovalidateMode.always
: AutovalidateMode.disabled,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 40),
// Title // Title
AppPasswordTextFormField( AppPasswordTextFormField(
title: 'Masukkan kata sandi', title: 'Masukkan kata sandi',
hintText: '********', hintText: '********',
), onChanged: (value) => context
SizedBox(height: 24), .read<SetPasswordFormBloc>()
AppPasswordTextFormField( .add(SetPasswordFormEvent.passwordChanged(value)),
title: 'Ulangi kata sandi', validator: (value) {
hintText: '********', if (context
), .read<SetPasswordFormBloc>()
.state
.password
.isEmpty) {
return 'Masukkan kata sandi';
}
const SizedBox(height: 50), return null;
},
),
SizedBox(height: 24),
AppPasswordTextFormField(
title: 'Ulangi kata sandi',
hintText: '********',
onChanged: (value) =>
context.read<SetPasswordFormBloc>().add(
SetPasswordFormEvent.confirmPasswordChanged(value),
),
validator: (value) {
if (context
.read<SetPasswordFormBloc>()
.state
.password
.isEmpty) {
return 'Masukkan kata sandi';
}
Spacer(), if (context
.read<SetPasswordFormBloc>()
.state
.password !=
context
.read<SetPasswordFormBloc>()
.state
.confirmPassword) {
return 'Kata sandi tidak cocok';
}
// Continue Button return null;
AppElevatedButton( },
onPressed: () => context.router.push(const MainRoute()), ),
title: 'Konfirmasi',
),
const SizedBox(height: 24), const SizedBox(height: 50),
],
Spacer(),
// Continue Button
AppElevatedButton(
onPressed: state.isSubmitting
? null
: () => context.read<SetPasswordFormBloc>().add(
SetPasswordFormEvent.submitted(),
),
title: 'Konfirmasi',
isLoading: state.isSubmitting,
),
const SizedBox(height: 24),
],
),
),
);
},
), ),
), ),
); );
} }
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) => getIt<SetPasswordFormBloc>()
..add(SetPasswordFormEvent.registrationTokenChanged(registrationToken)),
child: this,
);
} }
+111 -53
View File
@@ -1,78 +1,136 @@
import 'dart:developer';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/auth/check_phone_form/check_phone_form_bloc.dart';
import '../../../../common/function/app_function.dart';
import '../../../../common/theme/theme.dart'; import '../../../../common/theme/theme.dart';
import '../../../../domain/auth/auth.dart';
import '../../../../injection.dart';
import '../../../components/button/button.dart'; import '../../../components/button/button.dart';
import '../../../components/toast/flushbar.dart';
import '../../../router/app_router.gr.dart'; import '../../../router/app_router.gr.dart';
import 'widgets/phone_field.dart'; import 'widgets/phone_field.dart';
@RoutePage() @RoutePage()
class LoginPage extends StatelessWidget { class LoginPage extends StatelessWidget implements AutoRouteWrapper {
const LoginPage({super.key}); const LoginPage({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return BlocListener<CheckPhoneFormBloc, CheckPhoneFormState>(
appBar: AppBar(title: const Text('Masuk')), listenWhen: (p, c) =>
body: Padding( p.failureOrCheckPhoneOption != c.failureOrCheckPhoneOption,
padding: const EdgeInsets.symmetric(horizontal: 24.0), listener: (context, state) {
child: Column( state.failureOrCheckPhoneOption.fold(
crossAxisAlignment: CrossAxisAlignment.start, () => null,
children: [ (either) => either.fold(
const SizedBox(height: 40), (f) => AppFlushbar.showAuthFailureToast(context, f),
(data) {
// Title AppFlushbar.showSuccess(context, data.message);
LoginPhoneField(), Future.delayed(Duration(milliseconds: 1000), () {
log(data.toString());
const SizedBox(height: 50), if (data.status.isNotRegistered) {
context.router.push(
// Continue Button RegisterRoute(phoneNumber: data.phoneNumber),
AppElevatedButton( );
onPressed: () { } else if (data.status.isPasswordRequired) {
context.router.push(RegisterRoute()); context.router.push(
}, PasswordRoute(
title: 'Lanjutkan', phoneNumber: getNormalizePhone(state.phoneNumber),
), ),
);
const SizedBox(height: 24), }
});
// Terms and Conditions },
Center( ),
child: RichText( );
textAlign: TextAlign.center, },
text: TextSpan( child: Scaffold(
style: AppStyle.md.copyWith( appBar: AppBar(title: const Text('Masuk')),
color: AppColor.textSecondary, body: BlocBuilder<CheckPhoneFormBloc, CheckPhoneFormState>(
height: 1.4, builder: (context, state) {
), return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Form(
autovalidateMode: state.showErrorMessages
? AutovalidateMode.always
: AutovalidateMode.disabled,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const TextSpan( const SizedBox(height: 40),
text: 'Dengan masuk Enaklo, kamu telah\nmenyetujui ',
// Title
LoginPhoneField(),
const SizedBox(height: 50),
// Continue Button
AppElevatedButton(
onPressed: state.isSubmitting
? null
: () {
context.read<CheckPhoneFormBloc>().add(
CheckPhoneFormEvent.submitted(),
);
},
isLoading: state.isSubmitting,
title: 'Lanjutkan',
), ),
TextSpan(
text: 'Syarat & Ketentuan', const SizedBox(height: 24),
style: AppStyle.md.copyWith(
color: AppColor.primary, // Terms and Conditions
fontWeight: FontWeight.w600, Center(
), child: RichText(
), textAlign: TextAlign.center,
const TextSpan(text: ' dan\n'), text: TextSpan(
TextSpan( style: AppStyle.md.copyWith(
text: 'Kebijakan Privasi', color: AppColor.textSecondary,
style: AppStyle.md.copyWith( height: 1.4,
color: AppColor.primary, ),
fontWeight: FontWeight.w600, children: [
const TextSpan(
text:
'Dengan masuk Enaklo, kamu telah\nmenyetujui ',
),
TextSpan(
text: 'Syarat & Ketentuan',
style: AppStyle.md.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
),
),
const TextSpan(text: ' dan\n'),
TextSpan(
text: 'Kebijakan Privasi',
style: AppStyle.md.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
),
),
],
),
), ),
), ),
const SizedBox(height: 40),
], ],
), ),
), ),
), );
},
const SizedBox(height: 40),
],
), ),
), ),
); );
} }
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) => getIt<CheckPhoneFormBloc>(),
child: this,
);
} }
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../application/auth/check_phone_form/check_phone_form_bloc.dart';
import '../../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../components/field/field.dart'; import '../../../../components/field/field.dart';
@@ -45,6 +47,13 @@ class _LoginPhoneFieldState extends State<LoginPhoneField> {
controller: _controller, controller: _controller,
focusNode: _focusNode, focusNode: _focusNode,
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
validator: (value) {
if (context.read<CheckPhoneFormBloc>().state.phoneNumber.isEmpty) {
return 'Masukkan no telepon';
}
return null;
},
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12), padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text( child: Text(
@@ -64,7 +73,9 @@ class _LoginPhoneFieldState extends State<LoginPhoneField> {
) )
: null, : null,
onChanged: (value) { onChanged: (value) {
setState(() {}); context.read<CheckPhoneFormBloc>().add(
CheckPhoneFormEvent.phoneNumberChanged(value),
);
}, },
); );
} }
+200 -114
View File
@@ -2,16 +2,45 @@ import 'dart:async';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/auth/resend_form/resend_form_bloc.dart';
import '../../../../application/auth/verify_form/verify_form_bloc.dart';
import '../../../../common/theme/theme.dart'; import '../../../../common/theme/theme.dart';
import '../../../../domain/auth/auth.dart';
import '../../../../injection.dart';
import '../../../components/toast/flushbar.dart';
import '../../../router/app_router.gr.dart'; import '../../../router/app_router.gr.dart';
@RoutePage() @RoutePage()
class OtpPage extends StatefulWidget { class OtpPage extends StatefulWidget implements AutoRouteWrapper {
const OtpPage({super.key}); final String registrationToken;
final String phoneNumber;
const OtpPage({
super.key,
required this.registrationToken,
required this.phoneNumber,
});
@override @override
State<OtpPage> createState() => _OtpPageState(); State<OtpPage> createState() => _OtpPageState();
@override
Widget wrappedRoute(BuildContext context) => MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => getIt<VerifyFormBloc>()
..add(VerifyFormEvent.registrationTokenChanged(registrationToken)),
),
BlocProvider(
create: (context) => getIt<ResendFormBloc>()
..add(ResendFormEvent.phoneNumberChanged(phoneNumber))
..add(ResendFormEvent.purposeChanged('registration')),
),
],
child: this,
);
} }
class _OtpPageState extends State<OtpPage> { class _OtpPageState extends State<OtpPage> {
@@ -53,6 +82,7 @@ class _OtpPageState extends State<OtpPage> {
}); });
_startTimer(); _startTimer();
// Add your resend logic here // Add your resend logic here
context.read<ResendFormBloc>().add(ResendFormEvent.submitted());
} }
String _formatTime(int seconds) { String _formatTime(int seconds) {
@@ -82,7 +112,9 @@ class _OtpPageState extends State<OtpPage> {
void _verifyCode() { void _verifyCode() {
String code = _controllers.map((controller) => controller.text).join(); String code = _controllers.map((controller) => controller.text).join();
if (code.length == 6) { if (code.length == 6) {
context.router.push(CreatePasswordRoute()); // context.router.push(CreatePasswordRoute());
context.read<VerifyFormBloc>().add(VerifyFormEvent.otpCodeChanged(code));
context.read<VerifyFormBloc>().add(VerifyFormEvent.submitted());
} }
} }
@@ -100,135 +132,189 @@ class _OtpPageState extends State<OtpPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return MultiBlocListener(
appBar: AppBar(title: Text('Verifikasi')), listeners: [
body: Padding( BlocListener<VerifyFormBloc, VerifyFormState>(
padding: const EdgeInsets.symmetric(horizontal: 20.0), listenWhen: (p, c) =>
child: Column( p.failureOrVerifyOption != c.failureOrVerifyOption,
crossAxisAlignment: CrossAxisAlignment.start, listener: (context, state) {
children: [ state.failureOrVerifyOption.fold(
const SizedBox(height: 20), () {},
(either) => either.fold(
// Title (f) => AppFlushbar.showAuthFailureToast(context, f),
Text( (data) {
'Masukan Kode Verifikasi', if (data.status == "FAILED") {
style: AppStyle.xl.copyWith( AppFlushbar.showSuccess(context, data.message);
fontWeight: FontWeight.w600, Future.delayed(Duration(milliseconds: 1000), () {
color: AppColor.textPrimary, context.router.replaceAll([LoginRoute()]);
});
} else {
AppFlushbar.showSuccess(context, data.message);
Future.delayed(Duration(milliseconds: 1000), () {
context.router.push(
CreatePasswordRoute(
registrationToken: widget.registrationToken,
),
);
});
}
},
), ),
), );
},
),
BlocListener<ResendFormBloc, ResendFormState>(
listenWhen: (p, c) =>
p.failureOrResendOption != c.failureOrResendOption,
listener: (context, state) {
state.failureOrResendOption.fold(
() {},
(either) => either.fold(
(f) => AppFlushbar.showAuthFailureToast(context, f),
(data) {
if (data.status.isSuccess) {
AppFlushbar.showSuccess(context, data.message);
} else {
AppFlushbar.showError(context, data.message);
}
},
),
);
},
),
],
child: Scaffold(
appBar: AppBar(title: Text('Verifikasi')),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
const SizedBox(height: 12), // Title
Text(
'Masukan Kode Verifikasi',
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.textPrimary,
),
),
// Description const SizedBox(height: 12),
RichText(
text: TextSpan( // Description
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Kami telah mengirimkan kode verifikasi melalui ',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
height: 1.4,
),
),
TextSpan(
text: 'Whatsapp',
style: AppStyle.sm.copyWith(
color: AppColor.success,
fontWeight: FontWeight.w500,
height: 1.4,
),
),
TextSpan(
text: ' ke ',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
height: 1.4,
),
),
TextSpan(
text: '+${widget.phoneNumber}',
style: AppStyle.sm.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w500,
height: 1.4,
),
),
],
),
),
const SizedBox(height: 6),
// Hidden text fields for input
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(6, (index) {
return Expanded(
child: Padding(
padding: EdgeInsets.only(right: index == 5 ? 0 : 8.0),
child: TextFormField(
controller: _controllers[index],
focusNode: _focusNodes[index],
keyboardType: TextInputType.number,
maxLength: 1,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
decoration: InputDecoration(counterText: ''),
textAlign: TextAlign.center,
style: AppStyle.lg.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
),
cursorColor: AppColor.primary,
onChanged: (value) {
setState(() {});
_onCodeChanged(value, index);
},
),
),
);
}),
),
const SizedBox(height: 40),
// Timer and Resend Section
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
TextSpan( Text(
text: 'Kami telah mengirimkan kode verifikasi melalui ', 'Mohon tunggu untuk kirim ulang kode ',
style: AppStyle.sm.copyWith( style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
),
Text(
_formatTime(_secondsRemaining),
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary, color: AppColor.textSecondary,
height: 1.4,
),
),
TextSpan(
text: 'Whatsapp',
style: AppStyle.sm.copyWith(
color: AppColor.success,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
height: 1.4,
),
),
TextSpan(
text: ' ke ',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
height: 1.4,
),
),
TextSpan(
text: '+6288976680234',
style: AppStyle.sm.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w500,
height: 1.4,
), ),
), ),
], ],
), ),
),
const SizedBox(height: 6), if (_canResend) ...[
const SizedBox(height: 12),
// Hidden text fields for input Center(
Row( child: TextButton(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, onPressed: _resendCode,
children: List.generate(6, (index) { child: Text(
return Expanded( 'Kirim Ulang Kode',
child: Padding( style: AppStyle.sm.copyWith(
padding: EdgeInsets.only(right: index == 5 ? 0 : 8.0), color: AppColor.success,
child: TextFormField( fontWeight: FontWeight.w500,
controller: _controllers[index],
focusNode: _focusNodes[index],
keyboardType: TextInputType.number,
maxLength: 1,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: InputDecoration(counterText: ''),
textAlign: TextAlign.center,
style: AppStyle.lg.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
), ),
cursorColor: AppColor.primary,
onChanged: (value) {
setState(() {});
_onCodeChanged(value, index);
},
), ),
), ),
);
}),
),
const SizedBox(height: 40),
// Timer and Resend Section
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Mohon tunggu untuk kirim ulang kode ',
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
),
Text(
_formatTime(_secondsRemaining),
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
),
), ),
], ],
),
if (_canResend) ...[ const SizedBox(height: 24),
const SizedBox(height: 12),
Center(
child: TextButton(
onPressed: _resendCode,
child: Text(
'Kirim Ulang Kode',
style: AppStyle.sm.copyWith(
color: AppColor.success,
fontWeight: FontWeight.w500,
),
),
),
),
], ],
),
const SizedBox(height: 24),
],
), ),
), ),
); );
@@ -1,45 +1,105 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/auth/auth_bloc.dart';
import '../../../../application/auth/login_form/login_form_bloc.dart';
import '../../../../injection.dart';
import '../../../components/button/button.dart'; import '../../../components/button/button.dart';
import '../../../components/field/field.dart'; import '../../../components/field/field.dart';
import '../../../components/toast/flushbar.dart';
import '../../../router/app_router.gr.dart'; import '../../../router/app_router.gr.dart';
@RoutePage() @RoutePage()
class PasswordPage extends StatelessWidget { class PasswordPage extends StatelessWidget implements AutoRouteWrapper {
const PasswordPage({super.key}); final String phoneNumber;
const PasswordPage({super.key, required this.phoneNumber});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return BlocListener<LoginFormBloc, LoginFormState>(
appBar: AppBar(title: const Text('Buat Kata Sandi')), listenWhen: (p, c) => p.failureOrLoginOption != c.failureOrLoginOption,
body: Padding( listener: (context, state) {
padding: const EdgeInsets.symmetric(horizontal: 24.0), state.failureOrLoginOption.fold(
child: Column( () => null,
crossAxisAlignment: CrossAxisAlignment.start, (either) => either.fold(
children: [ (f) => AppFlushbar.showAuthFailureToast(context, f),
const SizedBox(height: 40), (data) {
AppFlushbar.showSuccess(context, data.message);
Future.delayed(Duration(milliseconds: 1000), () {
context.read<AuthBloc>().add(AuthEvent.fetchCurrentUser());
context.router.replaceAll([MainRoute()]);
});
},
),
);
},
child: Scaffold(
appBar: AppBar(title: const Text('Kata Sandi')),
body: BlocBuilder<LoginFormBloc, LoginFormState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Form(
autovalidateMode: state.showErrorMessages
? AutovalidateMode.always
: AutovalidateMode.disabled,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 40),
// Title // Title
AppPasswordTextFormField( AppPasswordTextFormField(
title: 'Masukkan kata sandi', title: 'Masukkan kata sandi',
hintText: '********', hintText: '********',
), onChanged: (value) => context.read<LoginFormBloc>().add(
LoginFormEvent.passwordChanged(value),
),
validator: (value) {
if (context
.read<LoginFormBloc>()
.state
.password
.isEmpty) {
return 'Masukkan kata sandi';
}
const SizedBox(height: 50), return null;
},
),
Spacer(), const SizedBox(height: 50),
// Continue Button Spacer(),
AppElevatedButton(
onPressed: () => context.router.push(const MainRoute()),
title: 'Konfirmasi',
),
const SizedBox(height: 24), // Continue Button
], AppElevatedButton(
onPressed: state.isSubmitting
? null
: () => context.read<LoginFormBloc>().add(
LoginFormEvent.submitted(),
),
title: 'Konfirmasi',
isLoading: state.isSubmitting,
),
const SizedBox(height: 24),
],
),
),
);
},
), ),
), ),
); );
} }
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) =>
getIt<LoginFormBloc>()
..add(LoginFormEvent.phoneNumberChanged(phoneNumber)),
child: this,
);
} }
@@ -1,45 +1,94 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/auth/register_form/register_form_bloc.dart';
import '../../../../injection.dart';
import '../../../components/button/button.dart'; import '../../../components/button/button.dart';
import '../../../components/toast/flushbar.dart';
import '../../../router/app_router.gr.dart'; import '../../../router/app_router.gr.dart';
import 'widgets/birth_date_field.dart';
import 'widgets/name_field.dart'; import 'widgets/name_field.dart';
import 'widgets/phone_field.dart';
@RoutePage() @RoutePage()
class RegisterPage extends StatelessWidget { class RegisterPage extends StatelessWidget implements AutoRouteWrapper {
const RegisterPage({super.key}); final String phoneNumber;
const RegisterPage({super.key, required this.phoneNumber});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return BlocListener<RegisterFormBloc, RegisterFormState>(
appBar: AppBar(title: const Text('Masuk')), listenWhen: (p, c) =>
body: Padding( p.failureOrRegisterOption != c.failureOrRegisterOption,
padding: const EdgeInsets.symmetric(horizontal: 24.0), listener: (context, state) {
child: Column( state.failureOrRegisterOption.fold(
crossAxisAlignment: CrossAxisAlignment.start, () {},
children: [ (either) => either.fold(
const SizedBox(height: 40), (f) => AppFlushbar.showAuthFailureToast(context, f),
(data) {
AppFlushbar.showSuccess(context, data.message);
Future.delayed(Duration(milliseconds: 1000), () {
context.router.push(
OtpRoute(
registrationToken: data.registrationToken,
phoneNumber: phoneNumber,
),
);
});
},
),
);
},
child: Scaffold(
appBar: AppBar(title: const Text('Daftar')),
body: BlocBuilder<RegisterFormBloc, RegisterFormState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Form(
autovalidateMode: state.showErrorMessages
? AutovalidateMode.always
: AutovalidateMode.disabled,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 40),
// Title RegisterNameField(),
RegisterPhoneField(), SizedBox(height: 24),
SizedBox(height: 24), RegisterBirthDateField(),
RegisterNameField(),
const SizedBox(height: 50), const SizedBox(height: 50),
Spacer(), Spacer(),
// Continue Button // Continue Button
AppElevatedButton( AppElevatedButton(
onPressed: () => context.router.push(const OtpRoute()), onPressed: state.isSubmitting
title: 'Daftar & Lanjutkan', ? null
), : () => context.read<RegisterFormBloc>().add(
RegisterFormEvent.submitted(),
),
title: 'Daftar & Lanjutkan',
isLoading: state.isSubmitting,
),
const SizedBox(height: 24), const SizedBox(height: 24),
], ],
),
),
);
},
), ),
), ),
); );
} }
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) =>
getIt<RegisterFormBloc>()
..add(RegisterFormEvent.phoneNumberChanged(phoneNumber)),
child: this,
);
} }

Some files were not shown because too many files have changed in this diff Show More