From 3b26b19b25c7980ec620d84807f92ef8d24e920c Mon Sep 17 00:00:00 2001 From: efrilm Date: Thu, 18 Sep 2025 07:16:56 +0700 Subject: [PATCH] Resend --- .../auth/resend_form/resend_form_bloc.dart | 59 ++ .../resend_form/resend_form_bloc.freezed.dart | 738 ++++++++++++++++++ .../auth/resend_form/resend_form_event.dart | 10 + .../auth/resend_form/resend_form_state.dart | 18 + lib/common/extension/extension.dart | 11 + lib/common/url/api_path.dart | 1 + lib/domain/auth/auth.dart | 14 + lib/domain/auth/auth.freezed.dart | 230 ++++++ lib/domain/auth/entities/resend_entity.dart | 20 + .../auth/repositories/i_auth_repository.dart | 5 + lib/infrastructure/auth/auth_dtos.dart | 1 + .../auth/auth_dtos.freezed.dart | 446 +++++++++++ lib/infrastructure/auth/auth_dtos.g.dart | 30 + .../datasources/remote_data_provider.dart | 24 + lib/infrastructure/auth/dto/resend_dto.dart | 36 + .../auth/repositories/auth_repository.dart | 24 + lib/injection.config.dart | 5 + 17 files changed, 1672 insertions(+) create mode 100644 lib/application/auth/resend_form/resend_form_bloc.dart create mode 100644 lib/application/auth/resend_form/resend_form_bloc.freezed.dart create mode 100644 lib/application/auth/resend_form/resend_form_event.dart create mode 100644 lib/application/auth/resend_form/resend_form_state.dart create mode 100644 lib/domain/auth/entities/resend_entity.dart create mode 100644 lib/infrastructure/auth/dto/resend_dto.dart diff --git a/lib/application/auth/resend_form/resend_form_bloc.dart b/lib/application/auth/resend_form/resend_form_bloc.dart new file mode 100644 index 0000000..1aecbdc --- /dev/null +++ b/lib/application/auth/resend_form/resend_form_bloc.dart @@ -0,0 +1,59 @@ +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 'resend_form_event.dart'; +part 'resend_form_state.dart'; +part 'resend_form_bloc.freezed.dart'; + +@injectable +class ResendFormBloc extends Bloc { + final IAuthRepository _repository; + ResendFormBloc(this._repository) : super(ResendFormState.initial()) { + on(_onResendFormEvent); + } + + Future _onResendFormEvent( + ResendFormEvent event, + Emitter emit, + ) { + return event.map( + phoneNumberChanged: (e) async { + emit( + state.copyWith( + phoneNumber: e.phoneNumber, + failureOrResendOption: none(), + ), + ); + }, + purposeChanged: (e) async { + emit(state.copyWith(purpose: e.purpose, failureOrResendOption: none())); + }, + submitted: (e) async { + Either? failureOrResend; + emit(state.copyWith(isSubmitting: true, failureOrResendOption: none())); + + final phoneNumberValid = state.phoneNumber.isNotEmpty; + final purposeValid = state.purpose.isNotEmpty; + + if (phoneNumberValid && purposeValid) { + failureOrResend = await _repository.resend( + phoneNumber: state.phoneNumber, + purpose: state.purpose, + ); + + emit( + state.copyWith( + isSubmitting: false, + failureOrResendOption: optionOf(failureOrResend), + ), + ); + } + emit(state.copyWith(showErrorMessages: true, isSubmitting: false)); + }, + ); + } +} diff --git a/lib/application/auth/resend_form/resend_form_bloc.freezed.dart b/lib/application/auth/resend_form/resend_form_bloc.freezed.dart new file mode 100644 index 0000000..65aefe4 --- /dev/null +++ b/lib/application/auth/resend_form/resend_form_bloc.freezed.dart @@ -0,0 +1,738 @@ +// 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 'resend_form_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +/// @nodoc +mixin _$ResendFormEvent { + @optionalTypeArgs + TResult when({ + required TResult Function(String phoneNumber) phoneNumberChanged, + required TResult Function(String purpose) purposeChanged, + required TResult Function() submitted, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String phoneNumber)? phoneNumberChanged, + TResult? Function(String purpose)? purposeChanged, + TResult? Function()? submitted, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String phoneNumber)? phoneNumberChanged, + TResult Function(String purpose)? purposeChanged, + TResult Function()? submitted, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_PhoneNumberChanged value) phoneNumberChanged, + required TResult Function(_PurposeChanged value) purposeChanged, + required TResult Function(_Submitted value) submitted, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult? Function(_PurposeChanged value)? purposeChanged, + TResult? Function(_Submitted value)? submitted, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult Function(_PurposeChanged value)? purposeChanged, + TResult Function(_Submitted value)? submitted, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ResendFormEventCopyWith<$Res> { + factory $ResendFormEventCopyWith( + ResendFormEvent value, + $Res Function(ResendFormEvent) then, + ) = _$ResendFormEventCopyWithImpl<$Res, ResendFormEvent>; +} + +/// @nodoc +class _$ResendFormEventCopyWithImpl<$Res, $Val extends ResendFormEvent> + implements $ResendFormEventCopyWith<$Res> { + _$ResendFormEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$PhoneNumberChangedImplCopyWith<$Res> { + factory _$$PhoneNumberChangedImplCopyWith( + _$PhoneNumberChangedImpl value, + $Res Function(_$PhoneNumberChangedImpl) then, + ) = __$$PhoneNumberChangedImplCopyWithImpl<$Res>; + @useResult + $Res call({String phoneNumber}); +} + +/// @nodoc +class __$$PhoneNumberChangedImplCopyWithImpl<$Res> + extends _$ResendFormEventCopyWithImpl<$Res, _$PhoneNumberChangedImpl> + implements _$$PhoneNumberChangedImplCopyWith<$Res> { + __$$PhoneNumberChangedImplCopyWithImpl( + _$PhoneNumberChangedImpl _value, + $Res Function(_$PhoneNumberChangedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? phoneNumber = null}) { + return _then( + _$PhoneNumberChangedImpl( + null == phoneNumber + ? _value.phoneNumber + : phoneNumber // ignore: cast_nullable_to_non_nullable + as String, + ), + ); + } +} + +/// @nodoc + +class _$PhoneNumberChangedImpl implements _PhoneNumberChanged { + const _$PhoneNumberChangedImpl(this.phoneNumber); + + @override + final String phoneNumber; + + @override + String toString() { + return 'ResendFormEvent.phoneNumberChanged(phoneNumber: $phoneNumber)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PhoneNumberChangedImpl && + (identical(other.phoneNumber, phoneNumber) || + other.phoneNumber == phoneNumber)); + } + + @override + int get hashCode => Object.hash(runtimeType, phoneNumber); + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$PhoneNumberChangedImplCopyWith<_$PhoneNumberChangedImpl> get copyWith => + __$$PhoneNumberChangedImplCopyWithImpl<_$PhoneNumberChangedImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String phoneNumber) phoneNumberChanged, + required TResult Function(String purpose) purposeChanged, + required TResult Function() submitted, + }) { + return phoneNumberChanged(phoneNumber); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String phoneNumber)? phoneNumberChanged, + TResult? Function(String purpose)? purposeChanged, + TResult? Function()? submitted, + }) { + return phoneNumberChanged?.call(phoneNumber); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String phoneNumber)? phoneNumberChanged, + TResult Function(String purpose)? purposeChanged, + TResult Function()? submitted, + required TResult orElse(), + }) { + if (phoneNumberChanged != null) { + return phoneNumberChanged(phoneNumber); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_PhoneNumberChanged value) phoneNumberChanged, + required TResult Function(_PurposeChanged value) purposeChanged, + required TResult Function(_Submitted value) submitted, + }) { + return phoneNumberChanged(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult? Function(_PurposeChanged value)? purposeChanged, + TResult? Function(_Submitted value)? submitted, + }) { + return phoneNumberChanged?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult Function(_PurposeChanged value)? purposeChanged, + TResult Function(_Submitted value)? submitted, + required TResult orElse(), + }) { + if (phoneNumberChanged != null) { + return phoneNumberChanged(this); + } + return orElse(); + } +} + +abstract class _PhoneNumberChanged implements ResendFormEvent { + const factory _PhoneNumberChanged(final String phoneNumber) = + _$PhoneNumberChangedImpl; + + String get phoneNumber; + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PhoneNumberChangedImplCopyWith<_$PhoneNumberChangedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$PurposeChangedImplCopyWith<$Res> { + factory _$$PurposeChangedImplCopyWith( + _$PurposeChangedImpl value, + $Res Function(_$PurposeChangedImpl) then, + ) = __$$PurposeChangedImplCopyWithImpl<$Res>; + @useResult + $Res call({String purpose}); +} + +/// @nodoc +class __$$PurposeChangedImplCopyWithImpl<$Res> + extends _$ResendFormEventCopyWithImpl<$Res, _$PurposeChangedImpl> + implements _$$PurposeChangedImplCopyWith<$Res> { + __$$PurposeChangedImplCopyWithImpl( + _$PurposeChangedImpl _value, + $Res Function(_$PurposeChangedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? purpose = null}) { + return _then( + _$PurposeChangedImpl( + null == purpose + ? _value.purpose + : purpose // ignore: cast_nullable_to_non_nullable + as String, + ), + ); + } +} + +/// @nodoc + +class _$PurposeChangedImpl implements _PurposeChanged { + const _$PurposeChangedImpl(this.purpose); + + @override + final String purpose; + + @override + String toString() { + return 'ResendFormEvent.purposeChanged(purpose: $purpose)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PurposeChangedImpl && + (identical(other.purpose, purpose) || other.purpose == purpose)); + } + + @override + int get hashCode => Object.hash(runtimeType, purpose); + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$PurposeChangedImplCopyWith<_$PurposeChangedImpl> get copyWith => + __$$PurposeChangedImplCopyWithImpl<_$PurposeChangedImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String phoneNumber) phoneNumberChanged, + required TResult Function(String purpose) purposeChanged, + required TResult Function() submitted, + }) { + return purposeChanged(purpose); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String phoneNumber)? phoneNumberChanged, + TResult? Function(String purpose)? purposeChanged, + TResult? Function()? submitted, + }) { + return purposeChanged?.call(purpose); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String phoneNumber)? phoneNumberChanged, + TResult Function(String purpose)? purposeChanged, + TResult Function()? submitted, + required TResult orElse(), + }) { + if (purposeChanged != null) { + return purposeChanged(purpose); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_PhoneNumberChanged value) phoneNumberChanged, + required TResult Function(_PurposeChanged value) purposeChanged, + required TResult Function(_Submitted value) submitted, + }) { + return purposeChanged(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult? Function(_PurposeChanged value)? purposeChanged, + TResult? Function(_Submitted value)? submitted, + }) { + return purposeChanged?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult Function(_PurposeChanged value)? purposeChanged, + TResult Function(_Submitted value)? submitted, + required TResult orElse(), + }) { + if (purposeChanged != null) { + return purposeChanged(this); + } + return orElse(); + } +} + +abstract class _PurposeChanged implements ResendFormEvent { + const factory _PurposeChanged(final String purpose) = _$PurposeChangedImpl; + + String get purpose; + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PurposeChangedImplCopyWith<_$PurposeChangedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$SubmittedImplCopyWith<$Res> { + factory _$$SubmittedImplCopyWith( + _$SubmittedImpl value, + $Res Function(_$SubmittedImpl) then, + ) = __$$SubmittedImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$SubmittedImplCopyWithImpl<$Res> + extends _$ResendFormEventCopyWithImpl<$Res, _$SubmittedImpl> + implements _$$SubmittedImplCopyWith<$Res> { + __$$SubmittedImplCopyWithImpl( + _$SubmittedImpl _value, + $Res Function(_$SubmittedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ResendFormEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$SubmittedImpl implements _Submitted { + const _$SubmittedImpl(); + + @override + String toString() { + return 'ResendFormEvent.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({ + required TResult Function(String phoneNumber) phoneNumberChanged, + required TResult Function(String purpose) purposeChanged, + required TResult Function() submitted, + }) { + return submitted(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String phoneNumber)? phoneNumberChanged, + TResult? Function(String purpose)? purposeChanged, + TResult? Function()? submitted, + }) { + return submitted?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String phoneNumber)? phoneNumberChanged, + TResult Function(String purpose)? purposeChanged, + TResult Function()? submitted, + required TResult orElse(), + }) { + if (submitted != null) { + return submitted(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_PhoneNumberChanged value) phoneNumberChanged, + required TResult Function(_PurposeChanged value) purposeChanged, + required TResult Function(_Submitted value) submitted, + }) { + return submitted(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult? Function(_PurposeChanged value)? purposeChanged, + TResult? Function(_Submitted value)? submitted, + }) { + return submitted?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_PhoneNumberChanged value)? phoneNumberChanged, + TResult Function(_PurposeChanged value)? purposeChanged, + TResult Function(_Submitted value)? submitted, + required TResult orElse(), + }) { + if (submitted != null) { + return submitted(this); + } + return orElse(); + } +} + +abstract class _Submitted implements ResendFormEvent { + const factory _Submitted() = _$SubmittedImpl; +} + +/// @nodoc +mixin _$ResendFormState { + String get phoneNumber => throw _privateConstructorUsedError; + String get purpose => throw _privateConstructorUsedError; + Option> get failureOrResendOption => + throw _privateConstructorUsedError; + bool get isSubmitting => throw _privateConstructorUsedError; + bool get showErrorMessages => throw _privateConstructorUsedError; + + /// Create a copy of ResendFormState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ResendFormStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ResendFormStateCopyWith<$Res> { + factory $ResendFormStateCopyWith( + ResendFormState value, + $Res Function(ResendFormState) then, + ) = _$ResendFormStateCopyWithImpl<$Res, ResendFormState>; + @useResult + $Res call({ + String phoneNumber, + String purpose, + Option> failureOrResendOption, + bool isSubmitting, + bool showErrorMessages, + }); +} + +/// @nodoc +class _$ResendFormStateCopyWithImpl<$Res, $Val extends ResendFormState> + implements $ResendFormStateCopyWith<$Res> { + _$ResendFormStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ResendFormState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? phoneNumber = null, + Object? purpose = null, + Object? failureOrResendOption = null, + Object? isSubmitting = null, + Object? showErrorMessages = null, + }) { + return _then( + _value.copyWith( + phoneNumber: null == phoneNumber + ? _value.phoneNumber + : phoneNumber // ignore: cast_nullable_to_non_nullable + as String, + purpose: null == purpose + ? _value.purpose + : purpose // ignore: cast_nullable_to_non_nullable + as String, + failureOrResendOption: null == failureOrResendOption + ? _value.failureOrResendOption + : failureOrResendOption // ignore: cast_nullable_to_non_nullable + as Option>, + isSubmitting: null == isSubmitting + ? _value.isSubmitting + : isSubmitting // ignore: cast_nullable_to_non_nullable + as bool, + showErrorMessages: null == showErrorMessages + ? _value.showErrorMessages + : showErrorMessages // ignore: cast_nullable_to_non_nullable + as bool, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ResendFormStateImplCopyWith<$Res> + implements $ResendFormStateCopyWith<$Res> { + factory _$$ResendFormStateImplCopyWith( + _$ResendFormStateImpl value, + $Res Function(_$ResendFormStateImpl) then, + ) = __$$ResendFormStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String phoneNumber, + String purpose, + Option> failureOrResendOption, + bool isSubmitting, + bool showErrorMessages, + }); +} + +/// @nodoc +class __$$ResendFormStateImplCopyWithImpl<$Res> + extends _$ResendFormStateCopyWithImpl<$Res, _$ResendFormStateImpl> + implements _$$ResendFormStateImplCopyWith<$Res> { + __$$ResendFormStateImplCopyWithImpl( + _$ResendFormStateImpl _value, + $Res Function(_$ResendFormStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ResendFormState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? phoneNumber = null, + Object? purpose = null, + Object? failureOrResendOption = null, + Object? isSubmitting = null, + Object? showErrorMessages = null, + }) { + return _then( + _$ResendFormStateImpl( + phoneNumber: null == phoneNumber + ? _value.phoneNumber + : phoneNumber // ignore: cast_nullable_to_non_nullable + as String, + purpose: null == purpose + ? _value.purpose + : purpose // ignore: cast_nullable_to_non_nullable + as String, + failureOrResendOption: null == failureOrResendOption + ? _value.failureOrResendOption + : failureOrResendOption // ignore: cast_nullable_to_non_nullable + as Option>, + isSubmitting: null == isSubmitting + ? _value.isSubmitting + : isSubmitting // ignore: cast_nullable_to_non_nullable + as bool, + showErrorMessages: null == showErrorMessages + ? _value.showErrorMessages + : showErrorMessages // ignore: cast_nullable_to_non_nullable + as bool, + ), + ); + } +} + +/// @nodoc + +class _$ResendFormStateImpl implements _ResendFormState { + const _$ResendFormStateImpl({ + required this.phoneNumber, + required this.purpose, + required this.failureOrResendOption, + this.isSubmitting = false, + this.showErrorMessages = false, + }); + + @override + final String phoneNumber; + @override + final String purpose; + @override + final Option> failureOrResendOption; + @override + @JsonKey() + final bool isSubmitting; + @override + @JsonKey() + final bool showErrorMessages; + + @override + String toString() { + return 'ResendFormState(phoneNumber: $phoneNumber, purpose: $purpose, failureOrResendOption: $failureOrResendOption, isSubmitting: $isSubmitting, showErrorMessages: $showErrorMessages)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ResendFormStateImpl && + (identical(other.phoneNumber, phoneNumber) || + other.phoneNumber == phoneNumber) && + (identical(other.purpose, purpose) || other.purpose == purpose) && + (identical(other.failureOrResendOption, failureOrResendOption) || + other.failureOrResendOption == failureOrResendOption) && + (identical(other.isSubmitting, isSubmitting) || + other.isSubmitting == isSubmitting) && + (identical(other.showErrorMessages, showErrorMessages) || + other.showErrorMessages == showErrorMessages)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + phoneNumber, + purpose, + failureOrResendOption, + isSubmitting, + showErrorMessages, + ); + + /// Create a copy of ResendFormState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ResendFormStateImplCopyWith<_$ResendFormStateImpl> get copyWith => + __$$ResendFormStateImplCopyWithImpl<_$ResendFormStateImpl>( + this, + _$identity, + ); +} + +abstract class _ResendFormState implements ResendFormState { + const factory _ResendFormState({ + required final String phoneNumber, + required final String purpose, + required final Option> failureOrResendOption, + final bool isSubmitting, + final bool showErrorMessages, + }) = _$ResendFormStateImpl; + + @override + String get phoneNumber; + @override + String get purpose; + @override + Option> get failureOrResendOption; + @override + bool get isSubmitting; + @override + bool get showErrorMessages; + + /// Create a copy of ResendFormState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ResendFormStateImplCopyWith<_$ResendFormStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/application/auth/resend_form/resend_form_event.dart b/lib/application/auth/resend_form/resend_form_event.dart new file mode 100644 index 0000000..0d6267b --- /dev/null +++ b/lib/application/auth/resend_form/resend_form_event.dart @@ -0,0 +1,10 @@ +part of 'resend_form_bloc.dart'; + +@freezed +class ResendFormEvent with _$ResendFormEvent { + const factory ResendFormEvent.phoneNumberChanged(String phoneNumber) = + _PhoneNumberChanged; + const factory ResendFormEvent.purposeChanged(String purpose) = + _PurposeChanged; + const factory ResendFormEvent.submitted() = _Submitted; +} diff --git a/lib/application/auth/resend_form/resend_form_state.dart b/lib/application/auth/resend_form/resend_form_state.dart new file mode 100644 index 0000000..92fdfd5 --- /dev/null +++ b/lib/application/auth/resend_form/resend_form_state.dart @@ -0,0 +1,18 @@ +part of 'resend_form_bloc.dart'; + +@freezed +class ResendFormState with _$ResendFormState { + const factory ResendFormState({ + required String phoneNumber, + required String purpose, + required Option> failureOrResendOption, + @Default(false) bool isSubmitting, + @Default(false) bool showErrorMessages, + }) = _ResendFormState; + + factory ResendFormState.initial() => ResendFormState( + phoneNumber: '', + purpose: '', + failureOrResendOption: none(), + ); +} diff --git a/lib/common/extension/extension.dart b/lib/common/extension/extension.dart index 90c7b9f..922c90a 100644 --- a/lib/common/extension/extension.dart +++ b/lib/common/extension/extension.dart @@ -15,4 +15,15 @@ extension StringExt on String { return CheckPhoneStatus.unknown; } } + + ResendStatus toResendStatus() { + switch (this) { + case 'RESEND_NOT_ALLOWED': + return ResendStatus.resendNotAllowed; + case 'SUCCESS': + return ResendStatus.success; + default: + return ResendStatus.unknown; + } + } } diff --git a/lib/common/url/api_path.dart b/lib/common/url/api_path.dart index d6d3a1c..a897741 100644 --- a/lib/common/url/api_path.dart +++ b/lib/common/url/api_path.dart @@ -4,4 +4,5 @@ class ApiPath { static String verify = '/api/v1/customer-auth/register/verify-otp'; static String setPassword = '/api/v1/customer-auth/register/set-password'; static String login = '/api/v1/customer-auth/register/login'; + static String resend = '/api/v1/customer-auth/register/resend-otp'; } diff --git a/lib/domain/auth/auth.dart b/lib/domain/auth/auth.dart index 7f05790..50cc7bd 100644 --- a/lib/domain/auth/auth.dart +++ b/lib/domain/auth/auth.dart @@ -9,6 +9,7 @@ part 'entities/check_phone_entity.dart'; part 'entities/register_entity.dart'; part 'entities/verify_entity.dart'; part 'entities/login_entity.dart'; +part 'entities/resend_entity.dart'; part 'failures/auth_failure.dart'; part 'repositories/i_auth_repository.dart'; @@ -24,3 +25,16 @@ extension CheckPhoneStatusX on CheckPhoneStatus { bool get isNotRegistered => this == CheckPhoneStatus.notRegistered; bool get isPasswordRequired => this == CheckPhoneStatus.passwordRequired; } + +enum ResendStatus { resendNotAllowed, success, unknown } + +extension ResendStatusX on ResendStatus { + String toStringType() => switch (this) { + ResendStatus.resendNotAllowed => 'RESEND_NOT_ALLOWED', + ResendStatus.success => 'SUCCESS', + ResendStatus.unknown => '', + }; + + bool get isResendNotAllowed => this == ResendStatus.resendNotAllowed; + bool get isSuccess => this == ResendStatus.success; +} diff --git a/lib/domain/auth/auth.freezed.dart b/lib/domain/auth/auth.freezed.dart index ba27219..5111655 100644 --- a/lib/domain/auth/auth.freezed.dart +++ b/lib/domain/auth/auth.freezed.dart @@ -1033,6 +1033,236 @@ abstract class _User implements User { throw _privateConstructorUsedError; } +/// @nodoc +mixin _$Resend { + String get status => throw _privateConstructorUsedError; + String get message => throw _privateConstructorUsedError; + String get otpToken => throw _privateConstructorUsedError; + int get expiresIn => throw _privateConstructorUsedError; + int get nextResendIn => throw _privateConstructorUsedError; + + /// Create a copy of Resend + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ResendCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ResendCopyWith<$Res> { + factory $ResendCopyWith(Resend value, $Res Function(Resend) then) = + _$ResendCopyWithImpl<$Res, Resend>; + @useResult + $Res call({ + String status, + String message, + String otpToken, + int expiresIn, + int nextResendIn, + }); +} + +/// @nodoc +class _$ResendCopyWithImpl<$Res, $Val extends Resend> + implements $ResendCopyWith<$Res> { + _$ResendCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of Resend + /// 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? otpToken = null, + Object? expiresIn = null, + Object? nextResendIn = 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, + otpToken: null == otpToken + ? _value.otpToken + : otpToken // ignore: cast_nullable_to_non_nullable + as String, + expiresIn: null == expiresIn + ? _value.expiresIn + : expiresIn // ignore: cast_nullable_to_non_nullable + as int, + nextResendIn: null == nextResendIn + ? _value.nextResendIn + : nextResendIn // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ResendImplCopyWith<$Res> implements $ResendCopyWith<$Res> { + factory _$$ResendImplCopyWith( + _$ResendImpl value, + $Res Function(_$ResendImpl) then, + ) = __$$ResendImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String status, + String message, + String otpToken, + int expiresIn, + int nextResendIn, + }); +} + +/// @nodoc +class __$$ResendImplCopyWithImpl<$Res> + extends _$ResendCopyWithImpl<$Res, _$ResendImpl> + implements _$$ResendImplCopyWith<$Res> { + __$$ResendImplCopyWithImpl( + _$ResendImpl _value, + $Res Function(_$ResendImpl) _then, + ) : super(_value, _then); + + /// Create a copy of Resend + /// 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? otpToken = null, + Object? expiresIn = null, + Object? nextResendIn = null, + }) { + return _then( + _$ResendImpl( + 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, + otpToken: null == otpToken + ? _value.otpToken + : otpToken // ignore: cast_nullable_to_non_nullable + as String, + expiresIn: null == expiresIn + ? _value.expiresIn + : expiresIn // ignore: cast_nullable_to_non_nullable + as int, + nextResendIn: null == nextResendIn + ? _value.nextResendIn + : nextResendIn // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc + +class _$ResendImpl implements _Resend { + const _$ResendImpl({ + required this.status, + required this.message, + required this.otpToken, + required this.expiresIn, + required this.nextResendIn, + }); + + @override + final String status; + @override + final String message; + @override + final String otpToken; + @override + final int expiresIn; + @override + final int nextResendIn; + + @override + String toString() { + return 'Resend(status: $status, message: $message, otpToken: $otpToken, expiresIn: $expiresIn, nextResendIn: $nextResendIn)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ResendImpl && + (identical(other.status, status) || other.status == status) && + (identical(other.message, message) || other.message == message) && + (identical(other.otpToken, otpToken) || + other.otpToken == otpToken) && + (identical(other.expiresIn, expiresIn) || + other.expiresIn == expiresIn) && + (identical(other.nextResendIn, nextResendIn) || + other.nextResendIn == nextResendIn)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + status, + message, + otpToken, + expiresIn, + nextResendIn, + ); + + /// Create a copy of Resend + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ResendImplCopyWith<_$ResendImpl> get copyWith => + __$$ResendImplCopyWithImpl<_$ResendImpl>(this, _$identity); +} + +abstract class _Resend implements Resend { + const factory _Resend({ + required final String status, + required final String message, + required final String otpToken, + required final int expiresIn, + required final int nextResendIn, + }) = _$ResendImpl; + + @override + String get status; + @override + String get message; + @override + String get otpToken; + @override + int get expiresIn; + @override + int get nextResendIn; + + /// Create a copy of Resend + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ResendImplCopyWith<_$ResendImpl> get copyWith => + throw _privateConstructorUsedError; +} + /// @nodoc mixin _$AuthFailure { @optionalTypeArgs diff --git a/lib/domain/auth/entities/resend_entity.dart b/lib/domain/auth/entities/resend_entity.dart new file mode 100644 index 0000000..1db9ab2 --- /dev/null +++ b/lib/domain/auth/entities/resend_entity.dart @@ -0,0 +1,20 @@ +part of '../auth.dart'; + +@freezed +class Resend with _$Resend { + const factory Resend({ + required String status, + required String message, + required String otpToken, + required int expiresIn, + required int nextResendIn, + }) = _Resend; + + factory Resend.empty() => const Resend( + status: '', + message: '', + otpToken: '', + expiresIn: 0, + nextResendIn: 0, + ); +} diff --git a/lib/domain/auth/repositories/i_auth_repository.dart b/lib/domain/auth/repositories/i_auth_repository.dart index b6f62be..af2076c 100644 --- a/lib/domain/auth/repositories/i_auth_repository.dart +++ b/lib/domain/auth/repositories/i_auth_repository.dart @@ -26,4 +26,9 @@ abstract class IAuthRepository { required String phoneNumber, required String password, }); + + Future> resend({ + required String phoneNumber, + required String purpose, + }); } diff --git a/lib/infrastructure/auth/auth_dtos.dart b/lib/infrastructure/auth/auth_dtos.dart index 41e7f45..04b765a 100644 --- a/lib/infrastructure/auth/auth_dtos.dart +++ b/lib/infrastructure/auth/auth_dtos.dart @@ -9,3 +9,4 @@ part 'dto/check_phone_dto.dart'; part 'dto/register_dto.dart'; part 'dto/verify_dto.dart'; part 'dto/login_dto.dart'; +part 'dto/resend_dto.dart'; diff --git a/lib/infrastructure/auth/auth_dtos.freezed.dart b/lib/infrastructure/auth/auth_dtos.freezed.dart index 2b118af..98d1193 100644 --- a/lib/infrastructure/auth/auth_dtos.freezed.dart +++ b/lib/infrastructure/auth/auth_dtos.freezed.dart @@ -1945,3 +1945,449 @@ abstract class _UserDto extends UserDto { _$$UserDtoImplCopyWith<_$UserDtoImpl> get copyWith => throw _privateConstructorUsedError; } + +ResendDto _$ResendDtoFromJson(Map json) { + return _ResendDto.fromJson(json); +} + +/// @nodoc +mixin _$ResendDto { + @JsonKey(name: 'status') + String? get status => throw _privateConstructorUsedError; + @JsonKey(name: 'message') + String? get message => throw _privateConstructorUsedError; + @JsonKey(name: 'data') + ResendDataDto? get data => throw _privateConstructorUsedError; + + /// Serializes this ResendDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ResendDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ResendDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ResendDtoCopyWith<$Res> { + factory $ResendDtoCopyWith(ResendDto value, $Res Function(ResendDto) then) = + _$ResendDtoCopyWithImpl<$Res, ResendDto>; + @useResult + $Res call({ + @JsonKey(name: 'status') String? status, + @JsonKey(name: 'message') String? message, + @JsonKey(name: 'data') ResendDataDto? data, + }); + + $ResendDataDtoCopyWith<$Res>? get data; +} + +/// @nodoc +class _$ResendDtoCopyWithImpl<$Res, $Val extends ResendDto> + implements $ResendDtoCopyWith<$Res> { + _$ResendDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ResendDto + /// 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 ResendDataDto?, + ) + as $Val, + ); + } + + /// Create a copy of ResendDto + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ResendDataDtoCopyWith<$Res>? get data { + if (_value.data == null) { + return null; + } + + return $ResendDataDtoCopyWith<$Res>(_value.data!, (value) { + return _then(_value.copyWith(data: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ResendDtoImplCopyWith<$Res> + implements $ResendDtoCopyWith<$Res> { + factory _$$ResendDtoImplCopyWith( + _$ResendDtoImpl value, + $Res Function(_$ResendDtoImpl) then, + ) = __$$ResendDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: 'status') String? status, + @JsonKey(name: 'message') String? message, + @JsonKey(name: 'data') ResendDataDto? data, + }); + + @override + $ResendDataDtoCopyWith<$Res>? get data; +} + +/// @nodoc +class __$$ResendDtoImplCopyWithImpl<$Res> + extends _$ResendDtoCopyWithImpl<$Res, _$ResendDtoImpl> + implements _$$ResendDtoImplCopyWith<$Res> { + __$$ResendDtoImplCopyWithImpl( + _$ResendDtoImpl _value, + $Res Function(_$ResendDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ResendDto + /// 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( + _$ResendDtoImpl( + 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 ResendDataDto?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$ResendDtoImpl extends _ResendDto { + const _$ResendDtoImpl({ + @JsonKey(name: 'status') this.status, + @JsonKey(name: 'message') this.message, + @JsonKey(name: 'data') this.data, + }) : super._(); + + factory _$ResendDtoImpl.fromJson(Map json) => + _$$ResendDtoImplFromJson(json); + + @override + @JsonKey(name: 'status') + final String? status; + @override + @JsonKey(name: 'message') + final String? message; + @override + @JsonKey(name: 'data') + final ResendDataDto? data; + + @override + String toString() { + return 'ResendDto(status: $status, message: $message, data: $data)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ResendDtoImpl && + (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 ResendDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ResendDtoImplCopyWith<_$ResendDtoImpl> get copyWith => + __$$ResendDtoImplCopyWithImpl<_$ResendDtoImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ResendDtoImplToJson(this); + } +} + +abstract class _ResendDto extends ResendDto { + const factory _ResendDto({ + @JsonKey(name: 'status') final String? status, + @JsonKey(name: 'message') final String? message, + @JsonKey(name: 'data') final ResendDataDto? data, + }) = _$ResendDtoImpl; + const _ResendDto._() : super._(); + + factory _ResendDto.fromJson(Map json) = + _$ResendDtoImpl.fromJson; + + @override + @JsonKey(name: 'status') + String? get status; + @override + @JsonKey(name: 'message') + String? get message; + @override + @JsonKey(name: 'data') + ResendDataDto? get data; + + /// Create a copy of ResendDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ResendDtoImplCopyWith<_$ResendDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +ResendDataDto _$ResendDataDtoFromJson(Map json) { + return _ResendDataDto.fromJson(json); +} + +/// @nodoc +mixin _$ResendDataDto { + @JsonKey(name: 'otp_token') + String? get otpToken => throw _privateConstructorUsedError; + @JsonKey(name: 'expires_in') + int? get expiresIn => throw _privateConstructorUsedError; + @JsonKey(name: 'next_resend_in') + int? get nextResendIn => throw _privateConstructorUsedError; + + /// Serializes this ResendDataDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ResendDataDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ResendDataDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ResendDataDtoCopyWith<$Res> { + factory $ResendDataDtoCopyWith( + ResendDataDto value, + $Res Function(ResendDataDto) then, + ) = _$ResendDataDtoCopyWithImpl<$Res, ResendDataDto>; + @useResult + $Res call({ + @JsonKey(name: 'otp_token') String? otpToken, + @JsonKey(name: 'expires_in') int? expiresIn, + @JsonKey(name: 'next_resend_in') int? nextResendIn, + }); +} + +/// @nodoc +class _$ResendDataDtoCopyWithImpl<$Res, $Val extends ResendDataDto> + implements $ResendDataDtoCopyWith<$Res> { + _$ResendDataDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ResendDataDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? otpToken = freezed, + Object? expiresIn = freezed, + Object? nextResendIn = freezed, + }) { + return _then( + _value.copyWith( + otpToken: freezed == otpToken + ? _value.otpToken + : otpToken // ignore: cast_nullable_to_non_nullable + as String?, + expiresIn: freezed == expiresIn + ? _value.expiresIn + : expiresIn // ignore: cast_nullable_to_non_nullable + as int?, + nextResendIn: freezed == nextResendIn + ? _value.nextResendIn + : nextResendIn // ignore: cast_nullable_to_non_nullable + as int?, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ResendDataDtoImplCopyWith<$Res> + implements $ResendDataDtoCopyWith<$Res> { + factory _$$ResendDataDtoImplCopyWith( + _$ResendDataDtoImpl value, + $Res Function(_$ResendDataDtoImpl) then, + ) = __$$ResendDataDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: 'otp_token') String? otpToken, + @JsonKey(name: 'expires_in') int? expiresIn, + @JsonKey(name: 'next_resend_in') int? nextResendIn, + }); +} + +/// @nodoc +class __$$ResendDataDtoImplCopyWithImpl<$Res> + extends _$ResendDataDtoCopyWithImpl<$Res, _$ResendDataDtoImpl> + implements _$$ResendDataDtoImplCopyWith<$Res> { + __$$ResendDataDtoImplCopyWithImpl( + _$ResendDataDtoImpl _value, + $Res Function(_$ResendDataDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ResendDataDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? otpToken = freezed, + Object? expiresIn = freezed, + Object? nextResendIn = freezed, + }) { + return _then( + _$ResendDataDtoImpl( + otpToken: freezed == otpToken + ? _value.otpToken + : otpToken // ignore: cast_nullable_to_non_nullable + as String?, + expiresIn: freezed == expiresIn + ? _value.expiresIn + : expiresIn // ignore: cast_nullable_to_non_nullable + as int?, + nextResendIn: freezed == nextResendIn + ? _value.nextResendIn + : nextResendIn // ignore: cast_nullable_to_non_nullable + as int?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$ResendDataDtoImpl implements _ResendDataDto { + const _$ResendDataDtoImpl({ + @JsonKey(name: 'otp_token') this.otpToken, + @JsonKey(name: 'expires_in') this.expiresIn, + @JsonKey(name: 'next_resend_in') this.nextResendIn, + }); + + factory _$ResendDataDtoImpl.fromJson(Map json) => + _$$ResendDataDtoImplFromJson(json); + + @override + @JsonKey(name: 'otp_token') + final String? otpToken; + @override + @JsonKey(name: 'expires_in') + final int? expiresIn; + @override + @JsonKey(name: 'next_resend_in') + final int? nextResendIn; + + @override + String toString() { + return 'ResendDataDto(otpToken: $otpToken, expiresIn: $expiresIn, nextResendIn: $nextResendIn)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ResendDataDtoImpl && + (identical(other.otpToken, otpToken) || + other.otpToken == otpToken) && + (identical(other.expiresIn, expiresIn) || + other.expiresIn == expiresIn) && + (identical(other.nextResendIn, nextResendIn) || + other.nextResendIn == nextResendIn)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, otpToken, expiresIn, nextResendIn); + + /// Create a copy of ResendDataDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ResendDataDtoImplCopyWith<_$ResendDataDtoImpl> get copyWith => + __$$ResendDataDtoImplCopyWithImpl<_$ResendDataDtoImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ResendDataDtoImplToJson(this); + } +} + +abstract class _ResendDataDto implements ResendDataDto { + const factory _ResendDataDto({ + @JsonKey(name: 'otp_token') final String? otpToken, + @JsonKey(name: 'expires_in') final int? expiresIn, + @JsonKey(name: 'next_resend_in') final int? nextResendIn, + }) = _$ResendDataDtoImpl; + + factory _ResendDataDto.fromJson(Map json) = + _$ResendDataDtoImpl.fromJson; + + @override + @JsonKey(name: 'otp_token') + String? get otpToken; + @override + @JsonKey(name: 'expires_in') + int? get expiresIn; + @override + @JsonKey(name: 'next_resend_in') + int? get nextResendIn; + + /// Create a copy of ResendDataDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ResendDataDtoImplCopyWith<_$ResendDataDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/infrastructure/auth/auth_dtos.g.dart b/lib/infrastructure/auth/auth_dtos.g.dart index a765194..6569175 100644 --- a/lib/infrastructure/auth/auth_dtos.g.dart +++ b/lib/infrastructure/auth/auth_dtos.g.dart @@ -133,3 +133,33 @@ Map _$$UserDtoImplToJson(_$UserDtoImpl instance) => 'phone_number': instance.phoneNumber, 'birth_date': instance.birthDate, }; + +_$ResendDtoImpl _$$ResendDtoImplFromJson(Map json) => + _$ResendDtoImpl( + status: json['status'] as String?, + message: json['message'] as String?, + data: json['data'] == null + ? null + : ResendDataDto.fromJson(json['data'] as Map), + ); + +Map _$$ResendDtoImplToJson(_$ResendDtoImpl instance) => + { + 'status': instance.status, + 'message': instance.message, + 'data': instance.data, + }; + +_$ResendDataDtoImpl _$$ResendDataDtoImplFromJson(Map json) => + _$ResendDataDtoImpl( + otpToken: json['otp_token'] as String?, + expiresIn: (json['expires_in'] as num?)?.toInt(), + nextResendIn: (json['next_resend_in'] as num?)?.toInt(), + ); + +Map _$$ResendDataDtoImplToJson(_$ResendDataDtoImpl instance) => + { + 'otp_token': instance.otpToken, + 'expires_in': instance.expiresIn, + 'next_resend_in': instance.nextResendIn, + }; diff --git a/lib/infrastructure/auth/datasources/remote_data_provider.dart b/lib/infrastructure/auth/datasources/remote_data_provider.dart index e65d2a8..259d96a 100644 --- a/lib/infrastructure/auth/datasources/remote_data_provider.dart +++ b/lib/infrastructure/auth/datasources/remote_data_provider.dart @@ -223,4 +223,28 @@ class AuthRemoteDataProvider { return DC.error(AuthFailure.serverError(e)); } } + + Future> resend({ + required String phoneNumber, + required String purpose, //login or registration + }) async { + try { + final response = await _apiClient.post( + ApiPath.resend, + data: {'phone_number': phoneNumber, 'purpose': purpose}, + ); + + if (response.data['success'] == false) { + return DC.error( + AuthFailure.dynamicErrorMessage('Terjadi kesalahan coba lagi nanti'), + ); + } + + final dto = ResendDto.fromJson(response.data['data']); + return DC.data(dto); + } on ApiFailure catch (e, s) { + log('resend', name: _logName, error: e, stackTrace: s); + return DC.error(AuthFailure.serverError(e)); + } + } } diff --git a/lib/infrastructure/auth/dto/resend_dto.dart b/lib/infrastructure/auth/dto/resend_dto.dart new file mode 100644 index 0000000..894f82d --- /dev/null +++ b/lib/infrastructure/auth/dto/resend_dto.dart @@ -0,0 +1,36 @@ +part of '../auth_dtos.dart'; + +@freezed +class ResendDto with _$ResendDto { + const factory ResendDto({ + @JsonKey(name: 'status') String? status, + @JsonKey(name: 'message') String? message, + @JsonKey(name: 'data') ResendDataDto? data, + }) = _ResendDto; + + factory ResendDto.fromJson(Map json) => + _$ResendDtoFromJson(json); + + const ResendDto._(); + + /// mapping ke domain + Resend toDomain() => Resend( + status: status ?? '', + message: message ?? '', + otpToken: data?.otpToken ?? '', + expiresIn: data?.expiresIn ?? 0, + nextResendIn: data?.nextResendIn ?? 0, + ); +} + +@freezed +class ResendDataDto with _$ResendDataDto { + const factory ResendDataDto({ + @JsonKey(name: 'otp_token') String? otpToken, + @JsonKey(name: 'expires_in') int? expiresIn, + @JsonKey(name: 'next_resend_in') int? nextResendIn, + }) = _ResendDataDto; + + factory ResendDataDto.fromJson(Map json) => + _$ResendDataDtoFromJson(json); +} diff --git a/lib/infrastructure/auth/repositories/auth_repository.dart b/lib/infrastructure/auth/repositories/auth_repository.dart index 782b3b7..6d58085 100644 --- a/lib/infrastructure/auth/repositories/auth_repository.dart +++ b/lib/infrastructure/auth/repositories/auth_repository.dart @@ -135,4 +135,28 @@ class AuthRepository implements IAuthRepository { return left(const AuthFailure.unexpectedError()); } } + + @override + Future> resend({ + required String phoneNumber, + required String purpose, + }) async { + try { + final result = await _remoteDataProvider.resend( + phoneNumber: phoneNumber, + purpose: purpose, + ); + + if (result.hasError) { + return left(result.error!); + } + + final auth = result.data!.toDomain(); + + return right(auth); + } catch (e, s) { + log('resendError', name: _logName, error: e, stackTrace: s); + return left(const AuthFailure.unexpectedError()); + } + } } diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 662589d..cfa831f 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -17,6 +17,8 @@ import 'package:enaklo/application/auth/login_form/login_form_bloc.dart' as _i510; import 'package:enaklo/application/auth/register_form/register_form_bloc.dart' as _i260; +import 'package:enaklo/application/auth/resend_form/resend_form_bloc.dart' + as _i627; import 'package:enaklo/application/auth/set_password/set_password_form_bloc.dart' as _i174; import 'package:enaklo/application/auth/verify_form/verify_form_bloc.dart' @@ -88,6 +90,9 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i174.SetPasswordFormBloc>( () => _i174.SetPasswordFormBloc(gh<_i995.IAuthRepository>()), ); + gh.factory<_i627.ResendFormBloc>( + () => _i627.ResendFormBloc(gh<_i995.IAuthRepository>()), + ); return this; } }