refactor(recover_password): type API errors and hide email enumeration
Map PUT /auth/reset-password and PUT /auth/recovery-password failures into LegacyRecoverPasswordErrorEvent. Reset-password now treats 404 (email not found) as success and surfaces a generic sent-if-exists flow, closing an account enumeration vector. Recovery-password differentiates 401 (tokenExpired), 404 (tokenNotFound), 403+Property (invalidField) from 403 without Property (weakPassword). The view state splits validation vs API errors with a displayErrorKey extension for the inline error text.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
||||
|
||||
enum LegacyRecoverPasswordErrorEvent {
|
||||
invalidEmail,
|
||||
invalidField,
|
||||
weakPassword,
|
||||
tokenExpired,
|
||||
tokenNotFound,
|
||||
tooManyAttempts,
|
||||
network,
|
||||
generic,
|
||||
}
|
||||
|
||||
/// For POST /auth/reset-password.
|
||||
///
|
||||
/// Returns `null` when the backend responds with 404 (email not found) to
|
||||
/// hide account enumeration — callers should treat this as success and show
|
||||
/// a generic "if the email exists, we sent a link" message.
|
||||
LegacyRecoverPasswordErrorEvent? mapResetPasswordError(Object error) {
|
||||
if (error is! ApiException) return LegacyRecoverPasswordErrorEvent.generic;
|
||||
if (error.isNetworkError) return LegacyRecoverPasswordErrorEvent.network;
|
||||
|
||||
switch (error.statusCode) {
|
||||
case 404:
|
||||
return null;
|
||||
case 403:
|
||||
return LegacyRecoverPasswordErrorEvent.invalidEmail;
|
||||
case 429:
|
||||
return LegacyRecoverPasswordErrorEvent.tooManyAttempts;
|
||||
default:
|
||||
return LegacyRecoverPasswordErrorEvent.generic;
|
||||
}
|
||||
}
|
||||
|
||||
LegacyRecoverPasswordErrorEvent mapRecoveryPasswordError(Object error) {
|
||||
if (error is! ApiException) return LegacyRecoverPasswordErrorEvent.generic;
|
||||
if (error.isNetworkError) return LegacyRecoverPasswordErrorEvent.network;
|
||||
|
||||
switch (error.statusCode) {
|
||||
case 401:
|
||||
return LegacyRecoverPasswordErrorEvent.tokenExpired;
|
||||
case 404:
|
||||
return LegacyRecoverPasswordErrorEvent.tokenNotFound;
|
||||
case 403:
|
||||
if (error.message.contains('Property')) {
|
||||
return LegacyRecoverPasswordErrorEvent.invalidField;
|
||||
}
|
||||
return LegacyRecoverPasswordErrorEvent.weakPassword;
|
||||
case 429:
|
||||
return LegacyRecoverPasswordErrorEvent.tooManyAttempts;
|
||||
default:
|
||||
return LegacyRecoverPasswordErrorEvent.generic;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:legacy_auth/src/features/recover_password/presentation/state/recover_password_view_model.dart';
|
||||
import 'package:legacy_auth/src/features/recover_password/presentation/state/recover_password_view_state.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@@ -175,10 +176,10 @@ class LegacyNewPasswordScreen extends ConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (viewState.errorMessage.isNotEmpty) ...[
|
||||
if (viewState.displayErrorKey != null) ...[
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
context.translate(viewState.errorMessage),
|
||||
context.translate(viewState.displayErrorKey!),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color.fromRGBO(239, 17, 17, 1),
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
import '../state/recover_password_view_model.dart';
|
||||
import '../state/recover_password_view_state.dart';
|
||||
|
||||
class LegacyRequestRecoveryScreen extends ConsumerWidget {
|
||||
final NavigationContract navigationContract;
|
||||
@@ -58,9 +59,9 @@ class LegacyRequestRecoveryScreen extends ConsumerWidget {
|
||||
SizedBox(
|
||||
height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28),
|
||||
),
|
||||
if (viewState.errorMessage.isNotEmpty) ...[
|
||||
if (viewState.displayErrorKey != null) ...[
|
||||
Text(
|
||||
context.translate(viewState.errorMessage),
|
||||
context.translate(viewState.displayErrorKey!),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color.fromRGBO(239, 17, 17, 1),
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:legacy_auth/src/features/recover_password/domain/entities/legacy_recover_password_error_event.dart';
|
||||
import 'package:legacy_auth/src/features/recover_password/domain/use_cases/recover_password_use_case.dart';
|
||||
import 'package:legacy_auth/src/features/recover_password/presentation/state/recover_password_view_state.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:sf_tracking/sf_tracking.dart';
|
||||
|
||||
import '../providers/recover_password_provider.dart';
|
||||
@@ -46,7 +46,8 @@ class LegacyRecoverPasswordViewModel
|
||||
void _onEmailChanged() {
|
||||
state = state.copyWith(
|
||||
email: emailController.text,
|
||||
errorMessage: '',
|
||||
validationErrorKey: '',
|
||||
apiErrorEvent: null,
|
||||
recoveryRequested: false,
|
||||
);
|
||||
}
|
||||
@@ -57,7 +58,8 @@ class LegacyRecoverPasswordViewModel
|
||||
|
||||
state = state.copyWith(
|
||||
password: raw,
|
||||
errorMessage: '',
|
||||
validationErrorKey: '',
|
||||
apiErrorEvent: null,
|
||||
equalPasswords: equalPasswords,
|
||||
securityChecks: {
|
||||
'min': raw.length >= 8,
|
||||
@@ -72,7 +74,8 @@ class LegacyRecoverPasswordViewModel
|
||||
final raw = repeatedPasswordController.text;
|
||||
state = state.copyWith(
|
||||
repeatedPassword: raw,
|
||||
errorMessage: '',
|
||||
validationErrorKey: '',
|
||||
apiErrorEvent: null,
|
||||
equalPasswords: raw == passwordController.text,
|
||||
);
|
||||
}
|
||||
@@ -81,17 +84,28 @@ class LegacyRecoverPasswordViewModel
|
||||
state = state.copyWith(passwordVisible: !state.passwordVisible);
|
||||
}
|
||||
|
||||
void clearApiError() {
|
||||
if (state.apiErrorEvent != null) state = state.copyWith(apiErrorEvent: null);
|
||||
}
|
||||
|
||||
void clearValidationError() {
|
||||
if (state.validationErrorKey.isNotEmpty) {
|
||||
state = state.copyWith(validationErrorKey: '');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> requestRecovery() async {
|
||||
final email = state.email.trim();
|
||||
|
||||
if (email.isEmpty) {
|
||||
state = state.copyWith(errorMessage: 'errorMessageContactIsEmpty');
|
||||
state = state.copyWith(validationErrorKey: 'errorMessageContactIsEmpty');
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: true,
|
||||
errorMessage: '',
|
||||
validationErrorKey: '',
|
||||
apiErrorEvent: null,
|
||||
recoveryRequested: false,
|
||||
);
|
||||
|
||||
@@ -110,9 +124,20 @@ class LegacyRecoverPasswordViewModel
|
||||
);
|
||||
} catch (e) {
|
||||
if (!ref.mounted) return;
|
||||
|
||||
final mappedError = mapResetPasswordError(e);
|
||||
if (mappedError == null) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetEmailSent());
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
recoveryRequested: true,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: I18n.errorGeneric,
|
||||
apiErrorEvent: mappedError,
|
||||
recoveryRequested: false,
|
||||
passwordChanged: false,
|
||||
);
|
||||
@@ -123,7 +148,7 @@ class LegacyRecoverPasswordViewModel
|
||||
if (!state.equalPasswords) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetFailed('unequal_passwords'));
|
||||
state = state.copyWith(
|
||||
errorMessage: 'errorMessageUnequalPasswords',
|
||||
validationErrorKey: 'errorMessageUnequalPasswords',
|
||||
passwordChanged: false,
|
||||
);
|
||||
return;
|
||||
@@ -132,7 +157,7 @@ class LegacyRecoverPasswordViewModel
|
||||
if (!state.securityChecks['min']!) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetFailed('too_short'));
|
||||
state = state.copyWith(
|
||||
errorMessage: 'errorMessagePasswordTooShort',
|
||||
validationErrorKey: 'errorMessagePasswordTooShort',
|
||||
passwordChanged: false,
|
||||
);
|
||||
return;
|
||||
@@ -141,7 +166,7 @@ class LegacyRecoverPasswordViewModel
|
||||
if (!state.securityChecks['capital']!) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetFailed('no_capitals'));
|
||||
state = state.copyWith(
|
||||
errorMessage: 'errorMessagePasswordNoCapitals',
|
||||
validationErrorKey: 'errorMessagePasswordNoCapitals',
|
||||
passwordChanged: false,
|
||||
);
|
||||
return;
|
||||
@@ -150,7 +175,7 @@ class LegacyRecoverPasswordViewModel
|
||||
if (!state.securityChecks['number']!) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetFailed('no_numbers'));
|
||||
state = state.copyWith(
|
||||
errorMessage: 'errorMessagePasswordNoNumbers',
|
||||
validationErrorKey: 'errorMessagePasswordNoNumbers',
|
||||
passwordChanged: false,
|
||||
);
|
||||
return;
|
||||
@@ -159,13 +184,17 @@ class LegacyRecoverPasswordViewModel
|
||||
if (!state.securityChecks['special']!) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetFailed('no_special_chars'));
|
||||
state = state.copyWith(
|
||||
errorMessage: 'errorMessagePasswordNoSpecialChars',
|
||||
validationErrorKey: 'errorMessagePasswordNoSpecialChars',
|
||||
passwordChanged: false,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: true, passwordChanged: false);
|
||||
state = state.copyWith(
|
||||
isLoading: true,
|
||||
apiErrorEvent: null,
|
||||
passwordChanged: false,
|
||||
);
|
||||
|
||||
try {
|
||||
await _recoverPasswordUseCase.recoverPassword(
|
||||
@@ -177,7 +206,7 @@ class LegacyRecoverPasswordViewModel
|
||||
} catch (error) {
|
||||
unawaited(_tracking.legacyAuthPasswordResetFailed(error.toString()));
|
||||
state = state.copyWith(
|
||||
errorMessage: I18n.errorGeneric,
|
||||
apiErrorEvent: mapRecoveryPasswordError(error),
|
||||
isLoading: false,
|
||||
passwordChanged: false,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:legacy_auth/src/features/recover_password/domain/entities/legacy_recover_password_error_event.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
|
||||
part 'recover_password_view_state.freezed.dart';
|
||||
|
||||
@@ -7,7 +9,8 @@ abstract class LegacyRecoverPasswordViewState
|
||||
with _$LegacyRecoverPasswordViewState {
|
||||
const factory LegacyRecoverPasswordViewState({
|
||||
@Default('') String email,
|
||||
@Default('') String errorMessage,
|
||||
@Default('') String validationErrorKey,
|
||||
LegacyRecoverPasswordErrorEvent? apiErrorEvent,
|
||||
@Default(false) bool isLoading,
|
||||
@Default(false) bool recoveryRequested,
|
||||
@Default(false) bool passwordChanged,
|
||||
@@ -25,3 +28,28 @@ abstract class LegacyRecoverPasswordViewState
|
||||
Map<String, bool> securityChecks,
|
||||
}) = _LegacyRecoverPasswordViewState;
|
||||
}
|
||||
|
||||
extension LegacyRecoverPasswordViewStateDisplay
|
||||
on LegacyRecoverPasswordViewState {
|
||||
String? get displayErrorKey {
|
||||
if (validationErrorKey.isNotEmpty) return validationErrorKey;
|
||||
final event = apiErrorEvent;
|
||||
if (event == null) return null;
|
||||
return switch (event) {
|
||||
LegacyRecoverPasswordErrorEvent.invalidEmail =>
|
||||
I18n.recoverPasswordErrorInvalidEmail,
|
||||
LegacyRecoverPasswordErrorEvent.invalidField =>
|
||||
I18n.recoverPasswordErrorInvalidField,
|
||||
LegacyRecoverPasswordErrorEvent.weakPassword =>
|
||||
I18n.recoverPasswordErrorWeakPassword,
|
||||
LegacyRecoverPasswordErrorEvent.tokenExpired =>
|
||||
I18n.recoverPasswordErrorTokenExpired,
|
||||
LegacyRecoverPasswordErrorEvent.tokenNotFound =>
|
||||
I18n.recoverPasswordErrorTokenNotFound,
|
||||
LegacyRecoverPasswordErrorEvent.tooManyAttempts =>
|
||||
I18n.authErrorTooManyAttempts,
|
||||
LegacyRecoverPasswordErrorEvent.network => I18n.authErrorNetwork,
|
||||
LegacyRecoverPasswordErrorEvent.generic => I18n.errorGeneric,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$LegacyRecoverPasswordViewState {
|
||||
|
||||
String get email; String get errorMessage; bool get isLoading; bool get recoveryRequested; bool get passwordChanged; String get token; String get password; String get repeatedPassword; bool get passwordVisible; bool get equalPasswords; Map<String, bool> get securityChecks;
|
||||
String get email; String get validationErrorKey; LegacyRecoverPasswordErrorEvent? get apiErrorEvent; bool get isLoading; bool get recoveryRequested; bool get passwordChanged; String get token; String get password; String get repeatedPassword; bool get passwordVisible; bool get equalPasswords; Map<String, bool> get securityChecks;
|
||||
/// Create a copy of LegacyRecoverPasswordViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $LegacyRecoverPasswordViewStateCopyWith<LegacyRecoverPasswordViewState> get copy
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is LegacyRecoverPasswordViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.token, token) || other.token == token)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&const DeepCollectionEquality().equals(other.securityChecks, securityChecks));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is LegacyRecoverPasswordViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.validationErrorKey, validationErrorKey) || other.validationErrorKey == validationErrorKey)&&(identical(other.apiErrorEvent, apiErrorEvent) || other.apiErrorEvent == apiErrorEvent)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.token, token) || other.token == token)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&const DeepCollectionEquality().equals(other.securityChecks, securityChecks));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,email,errorMessage,isLoading,recoveryRequested,passwordChanged,token,password,repeatedPassword,passwordVisible,equalPasswords,const DeepCollectionEquality().hash(securityChecks));
|
||||
int get hashCode => Object.hash(runtimeType,email,validationErrorKey,apiErrorEvent,isLoading,recoveryRequested,passwordChanged,token,password,repeatedPassword,passwordVisible,equalPasswords,const DeepCollectionEquality().hash(securityChecks));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LegacyRecoverPasswordViewState(email: $email, errorMessage: $errorMessage, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, token: $token, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, securityChecks: $securityChecks)';
|
||||
return 'LegacyRecoverPasswordViewState(email: $email, validationErrorKey: $validationErrorKey, apiErrorEvent: $apiErrorEvent, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, token: $token, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, securityChecks: $securityChecks)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract mixin class $LegacyRecoverPasswordViewStateCopyWith<$Res> {
|
||||
factory $LegacyRecoverPasswordViewStateCopyWith(LegacyRecoverPasswordViewState value, $Res Function(LegacyRecoverPasswordViewState) _then) = _$LegacyRecoverPasswordViewStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String email, String errorMessage, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks
|
||||
String email, String validationErrorKey, LegacyRecoverPasswordErrorEvent? apiErrorEvent, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks
|
||||
});
|
||||
|
||||
|
||||
@@ -62,11 +62,12 @@ class _$LegacyRecoverPasswordViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of LegacyRecoverPasswordViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? email = null,Object? errorMessage = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? token = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? securityChecks = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? email = null,Object? validationErrorKey = null,Object? apiErrorEvent = freezed,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? token = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? securityChecks = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable
|
||||
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as String,validationErrorKey: null == validationErrorKey ? _self.validationErrorKey : validationErrorKey // ignore: cast_nullable_to_non_nullable
|
||||
as String,apiErrorEvent: freezed == apiErrorEvent ? _self.apiErrorEvent : apiErrorEvent // ignore: cast_nullable_to_non_nullable
|
||||
as LegacyRecoverPasswordErrorEvent?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,recoveryRequested: null == recoveryRequested ? _self.recoveryRequested : recoveryRequested // ignore: cast_nullable_to_non_nullable
|
||||
as bool,passwordChanged: null == passwordChanged ? _self.passwordChanged : passwordChanged // ignore: cast_nullable_to_non_nullable
|
||||
as bool,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
@@ -160,10 +161,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String email, String errorMessage, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String email, String validationErrorKey, LegacyRecoverPasswordErrorEvent? apiErrorEvent, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LegacyRecoverPasswordViewState() when $default != null:
|
||||
return $default(_that.email,_that.errorMessage,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.securityChecks);case _:
|
||||
return $default(_that.email,_that.validationErrorKey,_that.apiErrorEvent,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.securityChecks);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -181,10 +182,10 @@ return $default(_that.email,_that.errorMessage,_that.isLoading,_that.recoveryReq
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String email, String errorMessage, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String email, String validationErrorKey, LegacyRecoverPasswordErrorEvent? apiErrorEvent, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LegacyRecoverPasswordViewState():
|
||||
return $default(_that.email,_that.errorMessage,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.securityChecks);case _:
|
||||
return $default(_that.email,_that.validationErrorKey,_that.apiErrorEvent,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.securityChecks);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -201,10 +202,10 @@ return $default(_that.email,_that.errorMessage,_that.isLoading,_that.recoveryReq
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String email, String errorMessage, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String email, String validationErrorKey, LegacyRecoverPasswordErrorEvent? apiErrorEvent, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LegacyRecoverPasswordViewState() when $default != null:
|
||||
return $default(_that.email,_that.errorMessage,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.securityChecks);case _:
|
||||
return $default(_that.email,_that.validationErrorKey,_that.apiErrorEvent,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.securityChecks);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -216,11 +217,12 @@ return $default(_that.email,_that.errorMessage,_that.isLoading,_that.recoveryReq
|
||||
|
||||
|
||||
class _LegacyRecoverPasswordViewState implements LegacyRecoverPasswordViewState {
|
||||
const _LegacyRecoverPasswordViewState({this.email = '', this.errorMessage = '', this.isLoading = false, this.recoveryRequested = false, this.passwordChanged = false, this.token = '', this.password = '', this.repeatedPassword = '', this.passwordVisible = false, this.equalPasswords = true, final Map<String, bool> securityChecks = const {'min' : false, 'capital' : false, 'number' : false, 'special' : false}}): _securityChecks = securityChecks;
|
||||
const _LegacyRecoverPasswordViewState({this.email = '', this.validationErrorKey = '', this.apiErrorEvent, this.isLoading = false, this.recoveryRequested = false, this.passwordChanged = false, this.token = '', this.password = '', this.repeatedPassword = '', this.passwordVisible = false, this.equalPasswords = true, final Map<String, bool> securityChecks = const {'min' : false, 'capital' : false, 'number' : false, 'special' : false}}): _securityChecks = securityChecks;
|
||||
|
||||
|
||||
@override@JsonKey() final String email;
|
||||
@override@JsonKey() final String errorMessage;
|
||||
@override@JsonKey() final String validationErrorKey;
|
||||
@override final LegacyRecoverPasswordErrorEvent? apiErrorEvent;
|
||||
@override@JsonKey() final bool isLoading;
|
||||
@override@JsonKey() final bool recoveryRequested;
|
||||
@override@JsonKey() final bool passwordChanged;
|
||||
@@ -247,16 +249,16 @@ _$LegacyRecoverPasswordViewStateCopyWith<_LegacyRecoverPasswordViewState> get co
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LegacyRecoverPasswordViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.token, token) || other.token == token)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&const DeepCollectionEquality().equals(other._securityChecks, _securityChecks));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LegacyRecoverPasswordViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.validationErrorKey, validationErrorKey) || other.validationErrorKey == validationErrorKey)&&(identical(other.apiErrorEvent, apiErrorEvent) || other.apiErrorEvent == apiErrorEvent)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.token, token) || other.token == token)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&const DeepCollectionEquality().equals(other._securityChecks, _securityChecks));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,email,errorMessage,isLoading,recoveryRequested,passwordChanged,token,password,repeatedPassword,passwordVisible,equalPasswords,const DeepCollectionEquality().hash(_securityChecks));
|
||||
int get hashCode => Object.hash(runtimeType,email,validationErrorKey,apiErrorEvent,isLoading,recoveryRequested,passwordChanged,token,password,repeatedPassword,passwordVisible,equalPasswords,const DeepCollectionEquality().hash(_securityChecks));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LegacyRecoverPasswordViewState(email: $email, errorMessage: $errorMessage, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, token: $token, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, securityChecks: $securityChecks)';
|
||||
return 'LegacyRecoverPasswordViewState(email: $email, validationErrorKey: $validationErrorKey, apiErrorEvent: $apiErrorEvent, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, token: $token, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, securityChecks: $securityChecks)';
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +269,7 @@ abstract mixin class _$LegacyRecoverPasswordViewStateCopyWith<$Res> implements $
|
||||
factory _$LegacyRecoverPasswordViewStateCopyWith(_LegacyRecoverPasswordViewState value, $Res Function(_LegacyRecoverPasswordViewState) _then) = __$LegacyRecoverPasswordViewStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String email, String errorMessage, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks
|
||||
String email, String validationErrorKey, LegacyRecoverPasswordErrorEvent? apiErrorEvent, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, Map<String, bool> securityChecks
|
||||
});
|
||||
|
||||
|
||||
@@ -284,11 +286,12 @@ class __$LegacyRecoverPasswordViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of LegacyRecoverPasswordViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? email = null,Object? errorMessage = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? token = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? securityChecks = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? email = null,Object? validationErrorKey = null,Object? apiErrorEvent = freezed,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? token = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? securityChecks = null,}) {
|
||||
return _then(_LegacyRecoverPasswordViewState(
|
||||
email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable
|
||||
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as String,validationErrorKey: null == validationErrorKey ? _self.validationErrorKey : validationErrorKey // ignore: cast_nullable_to_non_nullable
|
||||
as String,apiErrorEvent: freezed == apiErrorEvent ? _self.apiErrorEvent : apiErrorEvent // ignore: cast_nullable_to_non_nullable
|
||||
as LegacyRecoverPasswordErrorEvent?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,recoveryRequested: null == recoveryRequested ? _self.recoveryRequested : recoveryRequested // ignore: cast_nullable_to_non_nullable
|
||||
as bool,passwordChanged: null == passwordChanged ? _self.passwordChanged : passwordChanged // ignore: cast_nullable_to_non_nullable
|
||||
as bool,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
"authErrorTooManyAttempts": "Zu viele Versuche. Bitte warten Sie einige Minuten und versuchen Sie es erneut.",
|
||||
"authErrorNetwork": "Keine Verbindung. Überprüfen Sie Ihr Netzwerk und versuchen Sie es erneut.",
|
||||
"signupErrorInvalidField": "Eines der Felder ist ungültig. Bitte überprüfen Sie es und versuchen Sie es erneut.",
|
||||
"recoverPasswordErrorInvalidEmail": "Das E-Mail-Format ist ungültig.",
|
||||
"recoverPasswordErrorWeakPassword": "Das Passwort erfüllt die Sicherheitsanforderungen nicht.",
|
||||
"recoverPasswordErrorInvalidField": "Eines der Felder ist ungültig. Bitte überprüfen Sie es und versuchen Sie es erneut.",
|
||||
"recoverPasswordErrorTokenExpired": "Der Wiederherstellungslink ist abgelaufen. Bitte fordern Sie einen neuen an.",
|
||||
"recoverPasswordErrorTokenNotFound": "Der Wiederherstellungslink ist ungültig. Bitte fordern Sie einen neuen an.",
|
||||
"stepUserContactSupertitle": "Benutzer und Kontakt",
|
||||
"stepUserContactTitle": "Erstelle dein Konto",
|
||||
"stepUserContactSubtitle": "Mit deiner E-Mail und deiner Telefonnummer können wir dich jederzeit informieren",
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
"authErrorTooManyAttempts": "Too many attempts. Please wait a few minutes and try again.",
|
||||
"authErrorNetwork": "No connection. Check your network and try again.",
|
||||
"signupErrorInvalidField": "One of the fields is invalid. Please check and try again.",
|
||||
"recoverPasswordErrorInvalidEmail": "The email format is not valid.",
|
||||
"recoverPasswordErrorWeakPassword": "The password does not meet the security requirements.",
|
||||
"recoverPasswordErrorInvalidField": "One of the fields is invalid. Please check and try again.",
|
||||
"recoverPasswordErrorTokenExpired": "The recovery link has expired. Please request a new one.",
|
||||
"recoverPasswordErrorTokenNotFound": "The recovery link is not valid. Please request a new one.",
|
||||
"stepUserContactSupertitle": "User & contact",
|
||||
"stepUserContactTitle": "Create your account",
|
||||
"stepUserContactSubtitle": "With your email and phone number we can keep you informed at all times",
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
"authErrorTooManyAttempts": "Demasiados intentos. Espera unos minutos e inténtalo de nuevo.",
|
||||
"authErrorNetwork": "No hay conexión. Comprueba tu red e inténtalo de nuevo.",
|
||||
"signupErrorInvalidField": "Alguno de los campos no es válido. Revísalos e inténtalo de nuevo.",
|
||||
"recoverPasswordErrorInvalidEmail": "El email no tiene un formato válido.",
|
||||
"recoverPasswordErrorWeakPassword": "La contraseña no cumple los requisitos de seguridad.",
|
||||
"recoverPasswordErrorInvalidField": "Alguno de los campos no es válido. Revísalos e inténtalo de nuevo.",
|
||||
"recoverPasswordErrorTokenExpired": "El enlace de recuperación ha caducado. Solicita uno nuevo.",
|
||||
"recoverPasswordErrorTokenNotFound": "El enlace de recuperación no es válido. Solicita uno nuevo.",
|
||||
"stepUserContactSupertitle": "Usuario y contacto",
|
||||
"stepUserContactTitle": "Crea tu usuario",
|
||||
"stepUserContactSubtitle": "Con tu email y tu número podremos mantenerte siempre informado",
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
"authErrorTooManyAttempts": "Trop de tentatives. Patientez quelques minutes avant de réessayer.",
|
||||
"authErrorNetwork": "Pas de connexion. Vérifiez votre réseau et réessayez.",
|
||||
"signupErrorInvalidField": "L'un des champs n'est pas valide. Vérifiez et réessayez.",
|
||||
"recoverPasswordErrorInvalidEmail": "Le format de l'e-mail n'est pas valide.",
|
||||
"recoverPasswordErrorWeakPassword": "Le mot de passe ne respecte pas les exigences de sécurité.",
|
||||
"recoverPasswordErrorInvalidField": "L'un des champs n'est pas valide. Vérifiez et réessayez.",
|
||||
"recoverPasswordErrorTokenExpired": "Le lien de récupération a expiré. Demandez-en un nouveau.",
|
||||
"recoverPasswordErrorTokenNotFound": "Le lien de récupération n'est pas valide. Demandez-en un nouveau.",
|
||||
"stepUserContactSupertitle": "Utilisateur et contact",
|
||||
"stepUserContactTitle": "Crée ton compte",
|
||||
"stepUserContactSubtitle": "Avec ton e-mail et ton numéro, nous pourrons te tenir informé à tout moment",
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
"authErrorTooManyAttempts": "Troppi tentativi. Attendi qualche minuto e riprova.",
|
||||
"authErrorNetwork": "Nessuna connessione. Controlla la tua rete e riprova.",
|
||||
"signupErrorInvalidField": "Uno dei campi non è valido. Controlla e riprova.",
|
||||
"recoverPasswordErrorInvalidEmail": "Il formato dell'email non è valido.",
|
||||
"recoverPasswordErrorWeakPassword": "La password non soddisfa i requisiti di sicurezza.",
|
||||
"recoverPasswordErrorInvalidField": "Uno dei campi non è valido. Controlla e riprova.",
|
||||
"recoverPasswordErrorTokenExpired": "Il link di recupero è scaduto. Richiedine uno nuovo.",
|
||||
"recoverPasswordErrorTokenNotFound": "Il link di recupero non è valido. Richiedine uno nuovo.",
|
||||
"stepUserContactSupertitle": "Utente e contatti",
|
||||
"stepUserContactTitle": "Crea il tuo account",
|
||||
"stepUserContactSubtitle": "Con la tua email e il tuo numero potremo tenerti sempre informato",
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
"authErrorTooManyAttempts": "Demasiadas tentativas. Aguarda alguns minutos e tenta novamente.",
|
||||
"authErrorNetwork": "Sem ligação. Verifica a tua rede e tenta novamente.",
|
||||
"signupErrorInvalidField": "Um dos campos não é válido. Verifica e tenta novamente.",
|
||||
"recoverPasswordErrorInvalidEmail": "O formato do email não é válido.",
|
||||
"recoverPasswordErrorWeakPassword": "A palavra-passe não cumpre os requisitos de segurança.",
|
||||
"recoverPasswordErrorInvalidField": "Um dos campos não é válido. Verifica e tenta novamente.",
|
||||
"recoverPasswordErrorTokenExpired": "O link de recuperação expirou. Solicita um novo.",
|
||||
"recoverPasswordErrorTokenNotFound": "O link de recuperação não é válido. Solicita um novo.",
|
||||
"stepUserContactSupertitle": "Utilizador e contacto",
|
||||
"stepUserContactTitle": "Cria a tua conta",
|
||||
"stepUserContactSubtitle": "Com o teu email e o teu número poderemos manter-te sempre informado",
|
||||
|
||||
@@ -424,6 +424,16 @@ class I18n {
|
||||
static const String authErrorTooManyAttempts = 'authErrorTooManyAttempts';
|
||||
static const String authErrorNetwork = 'authErrorNetwork';
|
||||
static const String signupErrorInvalidField = 'signupErrorInvalidField';
|
||||
static const String recoverPasswordErrorInvalidEmail =
|
||||
'recoverPasswordErrorInvalidEmail';
|
||||
static const String recoverPasswordErrorWeakPassword =
|
||||
'recoverPasswordErrorWeakPassword';
|
||||
static const String recoverPasswordErrorInvalidField =
|
||||
'recoverPasswordErrorInvalidField';
|
||||
static const String recoverPasswordErrorTokenExpired =
|
||||
'recoverPasswordErrorTokenExpired';
|
||||
static const String recoverPasswordErrorTokenNotFound =
|
||||
'recoverPasswordErrorTokenNotFound';
|
||||
static const String errorGeofenceCreate = 'errorGeofenceCreate';
|
||||
static const String errorGeofenceDelete = 'errorGeofenceDelete';
|
||||
static const String errorGeofenceUpdate = 'errorGeofenceUpdate';
|
||||
|
||||
Reference in New Issue
Block a user