diff --git a/apps/mobile_app/lib/navigation/app_router.dart b/apps/mobile_app/lib/navigation/app_router.dart index 2d370280..da96b616 100644 --- a/apps/mobile_app/lib/navigation/app_router.dart +++ b/apps/mobile_app/lib/navigation/app_router.dart @@ -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, diff --git a/modules/legacy/modules/account/lib/src/core/data/datasource/account_remote_datasource_impl.dart b/modules/legacy/modules/account/lib/src/core/data/datasource/account_remote_datasource_impl.dart index 0f0af606..78c92f7e 100644 --- a/modules/legacy/modules/account/lib/src/core/data/datasource/account_remote_datasource_impl.dart +++ b/modules/legacy/modules/account/lib/src/core/data/datasource/account_remote_datasource_impl.dart @@ -23,7 +23,7 @@ class AccountRemoteDatasourceImpl implements AccountRemoteDatasource { @override Future> getLinkedDevices({required String userId}) async { try { - final response = await _repository.get>( + /*final response = await _repository.get>( '/$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( diff --git a/modules/legacy/modules/account/lib/src/core/domain/repositories/account_repository.dart b/modules/legacy/modules/account/lib/src/core/domain/repositories/account_repository.dart index 99ac924d..bfbf31e9 100644 --- a/modules/legacy/modules/account/lib/src/core/domain/repositories/account_repository.dart +++ b/modules/legacy/modules/account/lib/src/core/domain/repositories/account_repository.dart @@ -15,13 +15,17 @@ abstract class AccountRepository { required UpdateDeviceRequestEntity request }); - Future updateUser({required String userId, required UpdateUserRequestEntity request}); + Future updateUser({ + required String userId, + required UpdateUserRequestEntity request + }); Future> getAppUsers({required String userId}); Future deleteAppUser({required String userId}); - Future changePassword({required String userId, + Future changePassword({ + required String userId, required ChangePasswordRequestEntity request }); } diff --git a/modules/legacy/modules/account/lib/src/features/account_settings/presentation/account_settings_screen.dart b/modules/legacy/modules/account/lib/src/features/account_settings/presentation/account_settings_screen.dart index e25483fb..56f074d8 100644 --- a/modules/legacy/modules/account/lib/src/features/account_settings/presentation/account_settings_screen.dart +++ b/modules/legacy/modules/account/lib/src/features/account_settings/presentation/account_settings_screen.dart @@ -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 ), diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/delete_account_builder.dart b/modules/legacy/modules/account/lib/src/features/delete_account/delete_account_builder.dart new file mode 100644 index 00000000..7f5e95e8 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/delete_account_builder.dart @@ -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 buildPage(BuildContext context, GoRouterState state) { + final NavigationContract navigationContract = GetIt.I(); + + return MaterialPage( + key: state.pageKey, + child: DeleteAccountScreen(navigationContract: navigationContract), + ); + } +} diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/domain/delete_account_use_case.dart b/modules/legacy/modules/account/lib/src/features/delete_account/domain/delete_account_use_case.dart new file mode 100644 index 00000000..41dbe568 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/domain/delete_account_use_case.dart @@ -0,0 +1,6 @@ + +abstract class DeleteAccountUseCase { + Future deleteAccount({ + required String userId, + }); +} \ No newline at end of file diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/domain/delete_account_use_case_impl.dart b/modules/legacy/modules/account/lib/src/features/delete_account/domain/delete_account_use_case_impl.dart new file mode 100644 index 00000000..299cd6b8 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/domain/delete_account_use_case_impl.dart @@ -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 deleteAccount({required String userId}) { + return _repository.deleteAppUser(userId: userId); + } +} diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/presentation/delete_account_screen.dart b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/delete_account_screen.dart new file mode 100644 index 00000000..48ea4a75 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/delete_account_screen.dart @@ -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.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]; + } + +} diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/presentation/providers/delete_account_use_case_provider.dart b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/providers/delete_account_use_case_provider.dart new file mode 100644 index 00000000..75628c2e --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/providers/delete_account_use_case_provider.dart @@ -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((ref) { + final accountRepository = ref.read(accountRepositoryProvider); + return DeleteAccountUseCaseImpl(accountRepository); +}); diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_model.dart b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_model.dart new file mode 100644 index 00000000..ab0700f9 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_model.dart @@ -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.new, +); + +class DeleteAccountViewModel extends Notifier { + 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 devices) { + state = state.copyWith( + devices: devices, + deleteDevices: List.generate(devices.length, (_)=>false), + ); + } + + void updateDeleteDevice(int index) { + List 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 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(); + } +} \ No newline at end of file diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_state.dart b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_state.dart new file mode 100644 index 00000000..1b7e9ecb --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_state.dart @@ -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 devices, + @Default([]) List deleteDevices, + @Default('') String errorMessage, + }) = _DeleteAccountViewState; +} diff --git a/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_state.freezed.dart b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_state.freezed.dart new file mode 100644 index 00000000..c0c64d1b --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/delete_account/presentation/state/delete_account_view_state.freezed.dart @@ -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 value) => value; +/// @nodoc +mixin _$DeleteAccountViewState { + + UserEntity? get loggedUser; String get password; bool get isLoading; bool get isDeleted; int get confirmStep; List get devices; List 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 get copyWith => _$DeleteAccountViewStateCopyWithImpl(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 devices, List 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,deleteDevices: null == deleteDevices ? _self.deleteDevices : deleteDevices // ignore: cast_nullable_to_non_nullable +as List,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 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 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? 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 Function( UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List devices, List 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 Function( UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List devices, List 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? Function( UserEntity? loggedUser, String password, bool isLoading, bool isDeleted, int confirmStep, List devices, List 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 devices = const [], final List 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 _devices; +@override@JsonKey() List get devices { + if (_devices is EqualUnmodifiableListView) return _devices; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_devices); +} + + final List _deleteDevices; +@override@JsonKey() List 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 devices, List 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,deleteDevices: null == deleteDevices ? _self._deleteDevices : deleteDevices // ignore: cast_nullable_to_non_nullable +as List,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 diff --git a/modules/legacy/packages/legacy_shared/lib/src/data/datasource/legacy_shared_remote_datasource_impl.dart b/modules/legacy/packages/legacy_shared/lib/src/data/datasource/legacy_shared_remote_datasource_impl.dart index 30a09326..112dcc87 100644 --- a/modules/legacy/packages/legacy_shared/lib/src/data/datasource/legacy_shared_remote_datasource_impl.dart +++ b/modules/legacy/packages/legacy_shared/lib/src/data/datasource/legacy_shared_remote_datasource_impl.dart @@ -14,7 +14,7 @@ class LegacySharedRemoteDatasourceImpl implements LegacySharedRemoteDatasource { @override Future getLoggedUser({required String token}) async { try { - final response = await _repository.get>( + /*final response = await _repository.get>( '/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( diff --git a/modules/legacy/packages/legacy_shared/lib/src/providers/logged_user_provider.dart b/modules/legacy/packages/legacy_shared/lib/src/providers/logged_user_provider.dart index dde1f9ca..b39aa974 100644 --- a/modules/legacy/packages/legacy_shared/lib/src/providers/logged_user_provider.dart +++ b/modules/legacy/packages/legacy_shared/lib/src/providers/logged_user_provider.dart @@ -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 ); class LoggedUserNotifier extends AsyncNotifier { - late final legacySharedRepository; + late final LegacySharedRepository _legacySharedRepository; @override Future build() { - legacySharedRepository = ref.read(legacySharedRepositoryProvider); - return legacySharedRepository.getLoggedUser(token: ''); + _legacySharedRepository = ref.read(legacySharedRepositoryProvider); + return _legacySharedRepository.getLoggedUser(token: ''); } } diff --git a/packages/navigation/lib/app_routes.dart b/packages/navigation/lib/app_routes.dart index 205178f4..e33ad6e5 100644 --- a/packages/navigation/lib/app_routes.dart +++ b/packages/navigation/lib/app_routes.dart @@ -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'; diff --git a/packages/sf_localizations/assets/l10n/es.json b/packages/sf_localizations/assets/l10n/es.json index 1a142310..b6d9d71f 100644 --- a/packages/sf_localizations/assets/l10n/es.json +++ b/packages/sf_localizations/assets/l10n/es.json @@ -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" } \ No newline at end of file diff --git a/packages/sf_localizations/lib/src/generated/i18n.dart b/packages/sf_localizations/lib/src/generated/i18n.dart index d0631f95..70203512 100755 --- a/packages/sf_localizations/lib/src/generated/i18n.dart +++ b/packages/sf_localizations/lib/src/generated/i18n.dart @@ -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'; }