Delete account

This commit is contained in:
2026-02-26 17:01:19 +01:00
parent 8445af3f5a
commit 5a68dfb3df
17 changed files with 818 additions and 15 deletions

View File

@@ -94,6 +94,11 @@ void configureAppRouter() {
name: 'app_users',
pageBuilder: AppUsersBuilder().buildPage,
),
GoRoute(
path: AppRoutes.deleteAccount,
name: 'delete_account',
pageBuilder: DeleteAccountBuilder().buildPage,
),
GoRoute(
path: AppRoutes.customerService,

View File

@@ -23,7 +23,7 @@ class AccountRemoteDatasourceImpl implements AccountRemoteDatasource {
@override
Future<List<DeviceEntity>> getLinkedDevices({required String userId}) async {
try {
final response = await _repository.get<Map<String, dynamic>>(
/*final response = await _repository.get<Map<String, dynamic>>(
'/$userId/devices',
);
final data = response.data!['items'];
@@ -31,8 +31,8 @@ class AccountRemoteDatasourceImpl implements AccountRemoteDatasource {
throw Exception('Empty response from /:userId/devices');
}
final model = GetLinkedDevicesResponseModel.fromJson(data);
/*final model = GetLinkedDevicesResponseModel(items: [
final model = GetLinkedDevicesResponseModel.fromJson(data);*/
final model = GetLinkedDevicesResponseModel(items: [
GetLinkedDevicesItemResponseModel(
identificator: '1111',
carrierName: 'Carlos',
@@ -81,7 +81,7 @@ class AccountRemoteDatasourceImpl implements AccountRemoteDatasource {
isDisconnect: false,
)
),
]);*/
]);
return model.toEntity();
} on DioException catch (error) {
throw _mapDioError(

View File

@@ -15,13 +15,17 @@ abstract class AccountRepository {
required UpdateDeviceRequestEntity request
});
Future<void> updateUser({required String userId, required UpdateUserRequestEntity request});
Future<void> updateUser({
required String userId,
required UpdateUserRequestEntity request
});
Future<List<UserEntity>> getAppUsers({required String userId});
Future<void> deleteAppUser({required String userId});
Future<void> changePassword({required String userId,
Future<void> changePassword({
required String userId,
required ChangePasswordRequestEntity request
});
}

View File

@@ -86,7 +86,7 @@ class AccountSettingsScreen extends ConsumerWidget {
),
SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)),
AppSectionButton(
onPressed: (){},
onPressed: (){navigationContract.pushTo(AppRoutes.deleteAccount);},
icon: Icons.no_accounts,
text: I18n.legacyDeleteAccount
),

View File

@@ -0,0 +1,18 @@
import 'package:account/src/features/delete_account/presentation/delete_account_screen.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:get_it/get_it.dart';
import 'package:navigation/navigation.dart';
class DeleteAccountBuilder {
const DeleteAccountBuilder();
Page<void> buildPage(BuildContext context, GoRouterState state) {
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
return MaterialPage<void>(
key: state.pageKey,
child: DeleteAccountScreen(navigationContract: navigationContract),
);
}
}

View File

@@ -0,0 +1,6 @@
abstract class DeleteAccountUseCase {
Future<void> deleteAccount({
required String userId,
});
}

View File

@@ -0,0 +1,13 @@
import 'package:account/src/core/domain/repositories/account_repository.dart';
import 'package:account/src/features/delete_account/domain/delete_account_use_case.dart';
class DeleteAccountUseCaseImpl implements DeleteAccountUseCase {
DeleteAccountUseCaseImpl(this._repository);
final AccountRepository _repository;
@override
Future<void> deleteAccount({required String userId}) {
return _repository.deleteAppUser(userId: userId);
}
}

View File

@@ -0,0 +1,256 @@
import 'package:account/src/features/delete_account/presentation/state/delete_account_view_model.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:navigation/navigation.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:utils/utils.dart';
class DeleteAccountScreen extends ConsumerWidget {
final NavigationContract navigationContract;
const DeleteAccountScreen({super.key, required this.navigationContract});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themePortProvider);
final state = ref.watch(deleteAccountViewModelProvider);
final viewModel = ref.read(deleteAccountViewModelProvider.notifier);
return PageLayout(
title: context.translate(I18n.legacyDeleteAccount),
body: SingleChildScrollView(child: Container(
margin: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
Container(
color: theme.getColorFor(ThemeCode.backgroundSecondary),
width: double.infinity,
padding: SizeUtils.getByScreen(
small: EdgeInsets.symmetric(vertical: 20),
big: EdgeInsets.symmetric(vertical: 19),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
color: Color(0xFF00A1C6),
borderRadius: BorderRadius.circular(12)
),
padding: SizeUtils.getByScreen(
small: EdgeInsets.all(7),
big: EdgeInsets.all(6),
),
child: Icon(Icons.power_settings_new_outlined,
size: SizeUtils.getByScreen(small: 48, big: 46),
color: Colors.white,
),
),
Text(context.translate(I18n.legacyDeleteAccount),
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 20, big: 19)),
)
],
),
),
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 6)),
Text(context.translate(I18n.legacyDeleteAccountBody1),
textAlign: TextAlign.start,
),
SizedBox(height: SizeUtils.getByScreen(small: 38, big: 36)),
Text(context.translate(I18n.legacyDeleteAccountBody2),
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: theme.getColorFor(ThemeCode.textPrimary)
),
),
],
)
)),
footer: Container(
padding: SizeUtils.getByScreen(
small: EdgeInsets.symmetric(horizontal: 14, vertical: 10),
big: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
child: PrimaryButton(
onPressed: (){
if (state.loggedUser != null) {
showDialog(context: context, builder: (context) =>
Dialog(
backgroundColor: Colors.transparent,
child: ConfirmDialog(navigationContract: navigationContract),
)
);
}
},
text: context.translate(I18n.legacyRequestCancelButton),
color: Color(0xFF588EA5)
),
),
);
}
}
class ConfirmDialog extends ConsumerWidget{
final NavigationContract navigationContract;
const ConfirmDialog({
super.key,
required this.navigationContract,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(deleteAccountViewModelProvider);
final viewModel = ref.read(deleteAccountViewModelProvider.notifier);
final steps = [
Container(
height: 210,
width: 500,
color: Colors.white,
padding: SizeUtils.getByScreen(
small: EdgeInsets.symmetric(horizontal: 22, vertical: 11),
big: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(context.translate(I18n.legacyVerifyAccount),
style: TextStyle(
fontWeight: FontWeight.w500
),
),
SizedBox(height: SizeUtils.getByScreen(small: 18, big: 16)),
Text('${context.translate(I18n.email)}: ${state.loggedUser!.email}'),
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 6)),
Row(
children: [
Text('${context.translate(I18n.password)}: '),
SizedBox(width: SizeUtils.getByScreen(small: 12, big: 10)),
Expanded(child: TextField(
controller: viewModel.passwordController,
style: TextStyle(fontSize: 12),
decoration: InputDecoration(hintText: context.translate(I18n.password)),
obscureText: true,
enableSuggestions: false,
autocorrect: true,
))
],
),
if (state.errorMessage.isNotEmpty)
Text(
state.errorMessage,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 13,
),
),
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)),
Row(
children: [
Expanded(child: SecondaryButton(
onPressed: (){Navigator.pop(context);},
text: context.translate(I18n.legacyCancel),
color: Color(0xFF588EA5),
height: 40,
radius: 20,
)),
SizedBox(width: SizeUtils.getByScreen(small: 12, big: 10)),
Expanded(child: PrimaryButton(
onPressed: viewModel.nextStep,
text: context.translate(I18n.accept),
color: Color(0xFF588EA5),
height: 40,
radius: 20,
)),
],
)
],
),
),
Container(
height: 400,
width: 500,
color: Colors.white,
padding: SizeUtils.getByScreen(
small: EdgeInsets.symmetric(horizontal: 22, vertical: 11),
big: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(height: SizeUtils.getByScreen(small: 14, big: 12)),
Text(context.translate(I18n.legacyRequestCancelTitle),
style: TextStyle(
fontWeight: FontWeight.w500
),
),
SizedBox(height: SizeUtils.getByScreen(small: 14, big: 12)),
Expanded(child: SingleChildScrollView(child: Column(
children: [
Text(context.translate(I18n.legacyRequestCancelBody),
style: TextStyle(height: 1.5),
),
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)),
...List<Widget>.generate(state.devices.length, (int index) =>
CheckboxListTile(
contentPadding: EdgeInsets.zero,
title: Text(context.translate(I18n.legacyDeleteDeviceData,
args: {'name': state.devices[index].carrierName}
),
style: TextStyle(height: 0),
),
controlAffinity: ListTileControlAffinity.leading,
value: false,
onChanged: (_){
viewModel.updateDeleteDevice(index);
}
)
),
]
))),
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)),
Row(
children: [
Expanded(child: SecondaryButton(
onPressed: (){
viewModel.resetConfirmStep();
Navigator.pop(context);
},
text: context.translate(I18n.legacyCancel),
color: Color(0xFF588EA5),
height: 50,
radius: 25,
)),
SizedBox(width: SizeUtils.getByScreen(small: 12, big: 10)),
Expanded(child: PrimaryButton(
onPressed: () async {
viewModel.deleteAccount();
if (!context.mounted) return;
navigationContract.goTo(AppRoutes.login);
},
text: context.translate(I18n.legacyConfirm),
color: Color(0xFF588EA5),
height: 50,
radius: 25,
)),
],
)
],
),
)
];
return steps[state.confirmStep];
}
}

View File

@@ -0,0 +1,9 @@
import 'package:account/src/core/providers/account_repository_provider.dart';
import 'package:account/src/features/delete_account/domain/delete_account_use_case.dart';
import 'package:account/src/features/delete_account/domain/delete_account_use_case_impl.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final deleteAccountUseCaseProvider = Provider.autoDispose<DeleteAccountUseCase>((ref) {
final accountRepository = ref.read(accountRepositoryProvider);
return DeleteAccountUseCaseImpl(accountRepository);
});

View File

@@ -0,0 +1,128 @@
import 'package:account/src/features/delete_account/domain/delete_account_use_case.dart';
import 'package:account/src/features/delete_account/presentation/providers/delete_account_use_case_provider.dart';
import 'package:account/src/features/delete_account/presentation/state/delete_account_view_state.dart';
import 'package:account/src/features/linked_devices/domain/get_linked_devices_use_case.dart';
import 'package:account/src/features/linked_devices/presentation/providers/get_linked_devices_use_case_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
// import 'package:sf_localizations/sf_localizations.dart';
final deleteAccountViewModelProvider =
NotifierProvider.autoDispose<DeleteAccountViewModel, DeleteAccountViewState>(
DeleteAccountViewModel.new,
);
class DeleteAccountViewModel extends Notifier<DeleteAccountViewState> {
late final DeleteAccountUseCase _deleteAccountUseCase;
late final GetLinkedDevicesUseCase _getLinkedDevicesUseCase;
late final TextEditingController passwordController;
@override
DeleteAccountViewState build() {
_deleteAccountUseCase = ref.read(deleteAccountUseCaseProvider);
_getLinkedDevicesUseCase = ref.read(getLinkedDevicesUseCaseProvider);
passwordController = TextEditingController();
passwordController.addListener(_onPasswordChanged);
ref.read(loggedUserProvider.future)
.then((user){
setUser(user);
return _getLinkedDevicesUseCase.getLinkedDevices(userId: user.id);
}).then(setDevices);
ref.onDispose(disposeListeners);
return const DeleteAccountViewState();
}
void setUser(UserEntity user) {
state = state.copyWith(loggedUser: user);
}
void setDevices(List<DeviceEntity> devices) {
state = state.copyWith(
devices: devices,
deleteDevices: List<bool>.generate(devices.length, (_)=>false),
);
}
void updateDeleteDevice(int index) {
List<bool> deleteDevices = state.deleteDevices;
deleteDevices[index] = !deleteDevices[index];
state = state.copyWith(
deleteDevices: deleteDevices,
);
}
void _onPasswordChanged() {
final value = passwordController.text;
if (value == state.password) return;
state = state.copyWith(
password: value,
errorMessage: ''
);
}
bool _validateForm() {
if (state.password.trim().isEmpty) {
state = state.copyWith(errorMessage: 'errorMessagePasswordIsEmpty');
return false;
}
/*if (state.password.trim() != state.loggedUser.password.trim()) {
state = state.copyWith(errorMessage: 'errorMessagePasswordsDontMatch');
return false;
}*/
return true;
}
void nextStep() {
final step = state.confirmStep;
if (step == 0 && !_validateForm()) return;
state = state.copyWith(confirmStep: step + 1);
}
void resetConfirmStep() {
state = state.copyWith(confirmStep: 0);
}
Future<bool> deleteAccount() async {
if (state.isLoading) return false;
try {
state = state.copyWith(isLoading: true);
await _deleteAccountUseCase.deleteAccount(userId: state.loggedUser!.id);
if (!ref.mounted) return false;
ref.invalidate(loggedUserProvider);
state = state.copyWith(isLoading: false, isDeleted: true);
return true;
} catch (e) {
state = state.copyWith(isLoading: false);
if (!ref.mounted) return false;
_finishWithError(message: e.toString());
return false;
}
}
void _finishWithError({required String message}) {
state = state.copyWith(
isLoading: false,
errorMessage: message,
);
}
void disposeListeners() {
passwordController.removeListener(_onPasswordChanged);
passwordController.dispose();
}
}

View File

@@ -0,0 +1,18 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:legacy_shared/legacy_shared.dart';
part 'delete_account_view_state.freezed.dart';
@freezed
abstract class DeleteAccountViewState with _$DeleteAccountViewState {
const factory DeleteAccountViewState({
UserEntity? loggedUser,
@Default('') String password,
@Default(false) bool isLoading,
@Default(false) bool isDeleted,
@Default(0) int confirmStep,
@Default([]) List<DeviceEntity> devices,
@Default([]) List<bool> deleteDevices,
@Default('') String errorMessage,
}) = _DeleteAccountViewState;
}

View File

@@ -0,0 +1,328 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// 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 'delete_account_view_state.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$DeleteAccountViewState {
UserEntity? get loggedUser; String get password; bool get isLoading; bool get isDeleted; int get confirmStep; List<DeviceEntity> get devices; List<bool> get deleteDevices; String get errorMessage;
/// Create a copy of DeleteAccountViewState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$DeleteAccountViewStateCopyWith<DeleteAccountViewState> get copyWith => _$DeleteAccountViewStateCopyWithImpl<DeleteAccountViewState>(this as DeleteAccountViewState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is DeleteAccountViewState&&(identical(other.loggedUser, loggedUser) || other.loggedUser == loggedUser)&&(identical(other.password, password) || other.password == password)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isDeleted, isDeleted) || other.isDeleted == isDeleted)&&(identical(other.confirmStep, confirmStep) || other.confirmStep == confirmStep)&&const DeepCollectionEquality().equals(other.devices, devices)&&const DeepCollectionEquality().equals(other.deleteDevices, deleteDevices)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(runtimeType,loggedUser,password,isLoading,isDeleted,confirmStep,const DeepCollectionEquality().hash(devices),const DeepCollectionEquality().hash(deleteDevices),errorMessage);
@override
String toString() {
return 'DeleteAccountViewState(loggedUser: $loggedUser, password: $password, isLoading: $isLoading, isDeleted: $isDeleted, confirmStep: $confirmStep, devices: $devices, deleteDevices: $deleteDevices, errorMessage: $errorMessage)';
}
}
/// @nodoc
abstract mixin class $DeleteAccountViewStateCopyWith<$Res> {
factory $DeleteAccountViewStateCopyWith(DeleteAccountViewState value, $Res Function(DeleteAccountViewState) _then) = _$DeleteAccountViewStateCopyWithImpl;
@useResult
$Res call({
UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List<DeviceEntity> devices, List<bool> deleteDevices, String errorMessage
});
$UserEntityCopyWith<$Res>? get loggedUser;
}
/// @nodoc
class _$DeleteAccountViewStateCopyWithImpl<$Res>
implements $DeleteAccountViewStateCopyWith<$Res> {
_$DeleteAccountViewStateCopyWithImpl(this._self, this._then);
final DeleteAccountViewState _self;
final $Res Function(DeleteAccountViewState) _then;
/// Create a copy of DeleteAccountViewState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? loggedUser = freezed,Object? password = null,Object? isLoading = null,Object? isDeleted = null,Object? confirmStep = null,Object? devices = null,Object? deleteDevices = null,Object? errorMessage = null,}) {
return _then(_self.copyWith(
loggedUser: freezed == loggedUser ? _self.loggedUser : loggedUser // ignore: cast_nullable_to_non_nullable
as UserEntity?,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
as bool,isDeleted: null == isDeleted ? _self.isDeleted : isDeleted // ignore: cast_nullable_to_non_nullable
as bool,confirmStep: null == confirmStep ? _self.confirmStep : confirmStep // ignore: cast_nullable_to_non_nullable
as int,devices: null == devices ? _self.devices : devices // ignore: cast_nullable_to_non_nullable
as List<DeviceEntity>,deleteDevices: null == deleteDevices ? _self.deleteDevices : deleteDevices // ignore: cast_nullable_to_non_nullable
as List<bool>,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
as String,
));
}
/// Create a copy of DeleteAccountViewState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$UserEntityCopyWith<$Res>? get loggedUser {
if (_self.loggedUser == null) {
return null;
}
return $UserEntityCopyWith<$Res>(_self.loggedUser!, (value) {
return _then(_self.copyWith(loggedUser: value));
});
}
}
/// Adds pattern-matching-related methods to [DeleteAccountViewState].
extension DeleteAccountViewStatePatterns on DeleteAccountViewState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _DeleteAccountViewState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _DeleteAccountViewState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _DeleteAccountViewState value) $default,){
final _that = this;
switch (_that) {
case _DeleteAccountViewState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _DeleteAccountViewState value)? $default,){
final _that = this;
switch (_that) {
case _DeleteAccountViewState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List<DeviceEntity> devices, List<bool> deleteDevices, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _DeleteAccountViewState() when $default != null:
return $default(_that.loggedUser,_that.password,_that.isLoading,_that.isDeleted,_that.confirmStep,_that.devices,_that.deleteDevices,_that.errorMessage);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List<DeviceEntity> devices, List<bool> deleteDevices, String errorMessage) $default,) {final _that = this;
switch (_that) {
case _DeleteAccountViewState():
return $default(_that.loggedUser,_that.password,_that.isLoading,_that.isDeleted,_that.confirmStep,_that.devices,_that.deleteDevices,_that.errorMessage);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List<DeviceEntity> devices, List<bool> deleteDevices, String errorMessage)? $default,) {final _that = this;
switch (_that) {
case _DeleteAccountViewState() when $default != null:
return $default(_that.loggedUser,_that.password,_that.isLoading,_that.isDeleted,_that.confirmStep,_that.devices,_that.deleteDevices,_that.errorMessage);case _:
return null;
}
}
}
/// @nodoc
class _DeleteAccountViewState implements DeleteAccountViewState {
const _DeleteAccountViewState({this.loggedUser, this.password = '', this.isLoading = false, this.isDeleted = false, this.confirmStep = 0, final List<DeviceEntity> devices = const [], final List<bool> deleteDevices = const [], this.errorMessage = ''}): _devices = devices,_deleteDevices = deleteDevices;
@override final UserEntity? loggedUser;
@override@JsonKey() final String password;
@override@JsonKey() final bool isLoading;
@override@JsonKey() final bool isDeleted;
@override@JsonKey() final int confirmStep;
final List<DeviceEntity> _devices;
@override@JsonKey() List<DeviceEntity> get devices {
if (_devices is EqualUnmodifiableListView) return _devices;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_devices);
}
final List<bool> _deleteDevices;
@override@JsonKey() List<bool> get deleteDevices {
if (_deleteDevices is EqualUnmodifiableListView) return _deleteDevices;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_deleteDevices);
}
@override@JsonKey() final String errorMessage;
/// Create a copy of DeleteAccountViewState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$DeleteAccountViewStateCopyWith<_DeleteAccountViewState> get copyWith => __$DeleteAccountViewStateCopyWithImpl<_DeleteAccountViewState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DeleteAccountViewState&&(identical(other.loggedUser, loggedUser) || other.loggedUser == loggedUser)&&(identical(other.password, password) || other.password == password)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isDeleted, isDeleted) || other.isDeleted == isDeleted)&&(identical(other.confirmStep, confirmStep) || other.confirmStep == confirmStep)&&const DeepCollectionEquality().equals(other._devices, _devices)&&const DeepCollectionEquality().equals(other._deleteDevices, _deleteDevices)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(runtimeType,loggedUser,password,isLoading,isDeleted,confirmStep,const DeepCollectionEquality().hash(_devices),const DeepCollectionEquality().hash(_deleteDevices),errorMessage);
@override
String toString() {
return 'DeleteAccountViewState(loggedUser: $loggedUser, password: $password, isLoading: $isLoading, isDeleted: $isDeleted, confirmStep: $confirmStep, devices: $devices, deleteDevices: $deleteDevices, errorMessage: $errorMessage)';
}
}
/// @nodoc
abstract mixin class _$DeleteAccountViewStateCopyWith<$Res> implements $DeleteAccountViewStateCopyWith<$Res> {
factory _$DeleteAccountViewStateCopyWith(_DeleteAccountViewState value, $Res Function(_DeleteAccountViewState) _then) = __$DeleteAccountViewStateCopyWithImpl;
@override @useResult
$Res call({
UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List<DeviceEntity> devices, List<bool> deleteDevices, String errorMessage
});
@override $UserEntityCopyWith<$Res>? get loggedUser;
}
/// @nodoc
class __$DeleteAccountViewStateCopyWithImpl<$Res>
implements _$DeleteAccountViewStateCopyWith<$Res> {
__$DeleteAccountViewStateCopyWithImpl(this._self, this._then);
final _DeleteAccountViewState _self;
final $Res Function(_DeleteAccountViewState) _then;
/// Create a copy of DeleteAccountViewState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? loggedUser = freezed,Object? password = null,Object? isLoading = null,Object? isDeleted = null,Object? confirmStep = null,Object? devices = null,Object? deleteDevices = null,Object? errorMessage = null,}) {
return _then(_DeleteAccountViewState(
loggedUser: freezed == loggedUser ? _self.loggedUser : loggedUser // ignore: cast_nullable_to_non_nullable
as UserEntity?,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
as bool,isDeleted: null == isDeleted ? _self.isDeleted : isDeleted // ignore: cast_nullable_to_non_nullable
as bool,confirmStep: null == confirmStep ? _self.confirmStep : confirmStep // ignore: cast_nullable_to_non_nullable
as int,devices: null == devices ? _self._devices : devices // ignore: cast_nullable_to_non_nullable
as List<DeviceEntity>,deleteDevices: null == deleteDevices ? _self._deleteDevices : deleteDevices // ignore: cast_nullable_to_non_nullable
as List<bool>,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
as String,
));
}
/// Create a copy of DeleteAccountViewState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$UserEntityCopyWith<$Res>? get loggedUser {
if (_self.loggedUser == null) {
return null;
}
return $UserEntityCopyWith<$Res>(_self.loggedUser!, (value) {
return _then(_self.copyWith(loggedUser: value));
});
}
}
// dart format on

View File

@@ -14,7 +14,7 @@ class LegacySharedRemoteDatasourceImpl implements LegacySharedRemoteDatasource {
@override
Future<UserEntity> getLoggedUser({required String token}) async {
try {
final response = await _repository.get<Map<String, dynamic>>(
/*final response = await _repository.get<Map<String, dynamic>>(
'/users/api/auth/me',
);
final data = response.data!['item'];
@@ -22,13 +22,13 @@ class LegacySharedRemoteDatasourceImpl implements LegacySharedRemoteDatasource {
throw Exception('Empty response from /auth/me');
}
final model = GetLoggedUserResponseModel.fromJson(data);
/*final model = GetLoggedUserResponseModel(item:
final model = GetLoggedUserResponseModel.fromJson(data);*/
final model = GetLoggedUserResponseModel(item:
GetLoggedUserItemResponseModel(
id: '1111',
firstName: 'Juan',
email: 'juan@test.com',
phone: '111111111'));*/
phone: '111111111'));
return model.toEntity();
} on DioException catch (error) {
throw _mapDioError(

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/src/data/models/entities/user_entity.dart';
import 'package:legacy_shared/src/data/repositories/legacy_shared_repository.dart';
import 'legacy_shared_repository_provider.dart';
@@ -10,11 +11,11 @@ final loggedUserProvider = AsyncNotifierProvider<LoggedUserNotifier, UserEntity>
);
class LoggedUserNotifier extends AsyncNotifier<UserEntity> {
late final legacySharedRepository;
late final LegacySharedRepository _legacySharedRepository;
@override
Future<UserEntity> build() {
legacySharedRepository = ref.read(legacySharedRepositoryProvider);
return legacySharedRepository.getLoggedUser(token: '');
_legacySharedRepository = ref.read(legacySharedRepositoryProvider);
return _legacySharedRepository.getLoggedUser(token: '');
}
}

View File

@@ -24,6 +24,7 @@ class AppRoutes {
static const changePassword = '$accountSettings/change_password';
static const linkedDevices = '$accountSettings/linked_devices';
static const appUsers = '$accountSettings/app_users';
static const deleteAccount = '$accountSettings/delete_account';
static const legacyDashboard = '$legacy/dashboard';

View File

@@ -176,5 +176,13 @@
"userRole": "Rol: {role}",
"copy": "copiar",
"deviceIdLabel": "ID: {deviceId}",
"regCodeLabel": "Código de registro: {regCode}"
"regCodeLabel": "Código de registro: {regCode}",
"deleteAccountBody1": "Cancelar una cuenta es una operación irreversible. Confirma que todos los servicios relacionados con la cuenta se hayan gestionado correctamente.\n\nDespués de cancelar tu cuenta, ya no podrás usar esta cuenta ni recuperar ningún contenido o información que hayas agregado o vinculado (incluso si usas la misma cuenta para registrarse y volver a usar), incluídos, entre otros:\n1. No podrás iniciar sesión y usar esta cuenta.\n2. La información personal y la información histórica de tu cuenta no se recuperarán.\n3. No se pueden recuperar todos los registros de servicios de terceros que utiliza a través de la vinculación de cuenta o la vinculación de cuenta. Ya no podrás iniciar sesión y utilizar los servicios mencionados anteriormente. El amor, las monedas de oro, los puntos de terceros, los pedidos, los boletos y otros cupones que hayas recibido se considerarán abandonados y no se utilizarán.\n\nTen en cuenta que cancelar tu cuenta no significa que el comportamiento de la cuenta y las responsabilidades relacionadas antes de la cancelación de esta cuenta estén exentas o reducidas.",
"deleteAccountBody2": "Hacer clic en \"Solicitar la cancelación de mi cuenta\" significa que has leído y estás de acuerdo con la descripción anterior.",
"requestCancelButton": "Solicitar la cancelación de mi cuenta",
"verifyAccount": "Verificación de la cuenta,",
"requestCancelTitle": "Solicitud de cancelación de la cuenta",
"requestCancelBody": "1. La cancelación de la cuenta no es la recuperación operacional, asegúrate de que antes de operar la cuenta ya no se utiliza.\n2. Enviado correctamente una cancelación de la cuenta de la aplicación, la plataforma se eliminará toda la información relacionada con tu cuenta dentro de 1 hora.",
"deleteDeviceData": "Borrar toda la información relacionada con el dispositivo de {name}",
"confirm": "Confirmar"
}

View File

@@ -207,4 +207,12 @@ class I18n {
static const String legacyRegCodeLabel = 'regCodeLabel';
static const String legacyRegCode = 'regCode';
static const String legacyDeleteAccount = 'deleteAccount';
static const String legacyDeleteAccountBody1 = 'deleteAccountBody1';
static const String legacyDeleteAccountBody2 = 'deleteAccountBody2';
static const String legacyRequestCancelButton = 'requestCancelButton';
static const String legacyVerifyAccount = 'verifyAccount';
static const String legacyRequestCancelTitle = 'requestCancelTitle';
static const String legacyRequestCancelBody = 'requestCancelBody';
static const String legacyDeleteDeviceData = 'deleteDeviceData';
static const String legacyConfirm = 'confirm';
}