diff --git a/apps/mobile_app/lib/main.dart b/apps/mobile_app/lib/main.dart index a4f34335..d37ac1b1 100644 --- a/apps/mobile_app/lib/main.dart +++ b/apps/mobile_app/lib/main.dart @@ -80,7 +80,7 @@ class PlatformAppState extends ConsumerState routerConfig: appRouter, debugShowCheckedModeBanner: false, localizationsDelegates: [ - // CountryLocalizations.getDelegate(enableLocalization: false), + // CountryLocalizations.delegate, SFLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, diff --git a/apps/mobile_app/lib/navigation/app_router.dart b/apps/mobile_app/lib/navigation/app_router.dart index 85b8aaa2..a9d2a663 100644 --- a/apps/mobile_app/lib/navigation/app_router.dart +++ b/apps/mobile_app/lib/navigation/app_router.dart @@ -103,6 +103,13 @@ void configureAppRouter() { path: AppRoutes.dashboardProfile, name: 'profile', pageBuilder: const ProfileBuilder().buildPage, + routes: [ + GoRoute( + path: 'settings', + name: 'profile_settings', + pageBuilder: const ProfileSettingsBuilder().buildPage, + ), + ], ), ], ), diff --git a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart index 7511b89c..1e9e3468 100644 --- a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart +++ b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart @@ -1,14 +1,10 @@ import 'package:auth/src/core/data/models/child_profile_response_model.dart'; -import 'package:auth/src/core/data/models/payment_profile_response_model.dart'; -import 'package:auth/src/core/data/models/user_response_model.dart'; import 'package:auth/src/core/data/models/sign_up_request_model.dart'; import 'package:auth/src/core/data/models/sign_up_response_model.dart'; import 'package:auth/src/core/data/models/two_fa_secret_response_model.dart'; import 'package:auth/src/core/data/models/login_response_model.dart'; abstract class AuthRemoteDatasource { - Future getUserInfo(); - Future requestPhoneCode({required String phone}); Future verifyPhoneCode({required String phone, required String code}); @@ -44,8 +40,6 @@ abstract class AuthRemoteDatasource { Future createWallet(); - Future getPaymentProfile({required String userId}); - Future createChildProfile({ required String id, required String parentId, diff --git a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart index 1d2019f8..4fe14bf2 100644 --- a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart +++ b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart @@ -1,8 +1,6 @@ import 'dart:convert'; import 'package:auth/src/core/data/models/child_profile_response_model.dart'; -import 'package:auth/src/core/data/models/payment_profile_response_model.dart'; -import 'package:auth/src/core/data/models/user_response_model.dart'; import 'package:auth/src/core/data/models/sign_up_request_model.dart'; import 'package:auth/src/core/data/models/sign_up_response_model.dart'; import 'package:auth/src/core/data/models/two_fa_secret_response_model.dart'; @@ -17,22 +15,6 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource { AuthRemoteDatasourceImpl(this._repository); final QuestiaRepository _repository; - @override - Future getUserInfo() async { - try { - final response = await _repository.get>('/auth/me'); - - final data = response.data; - if (data == null || data.isEmpty) { - throw Exception('Empty response from /auth/me'); - } - - final parsed = UserResponseModel.fromJson(data); - return parsed.item; - } on DioException catch (error) { - throw _mapDioError(error, defaultMessage: 'Error in /auth/me'); - } - } @override Future requestPhoneCode({required String phone}) async { @@ -283,29 +265,6 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource { } } - @override - Future getPaymentProfile({ - required String userId, - }) async { - try { - final response = await _repository.get>( - '/users/$userId/payment-profile', - ); - - final data = response.data; - if (data == null || data.isEmpty) { - throw Exception('Empty response from /users/$userId/payment-profile'); - } - - return PaymentProfileResponseModel.fromJson(data); - } on DioException catch (error) { - throw _mapDioError( - error, - defaultMessage: 'Error in /users/$userId/payment-profile', - ); - } - } - @override Future createChildProfile({ required String id, diff --git a/modules/auth/lib/src/core/data/mappers/user_model_mapper.dart b/modules/auth/lib/src/core/data/mappers/user_model_mapper.dart deleted file mode 100644 index f862a65d..00000000 --- a/modules/auth/lib/src/core/data/mappers/user_model_mapper.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:auth/src/core/data/models/user_response_model.dart'; -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; - -extension UserModelMapper on UserModel { - UserEntity toEntity() { - return UserEntity( - id: id, - delegationId: delegationId, - email: email, - createdAt: createdAt, - updatedAt: updatedAt, - status: status, - role: role, - lastLogin: lastLogin, - currentLogin: currentLogin, - language: language, - firstName: firstName, - lastName: lastName, - hasApiKey: hasApiKey, - phone: phone, - ); - } -} diff --git a/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart b/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart index 6f9e09ce..2e8236ba 100644 --- a/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart +++ b/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart @@ -1,15 +1,11 @@ import 'package:auth/src/core/data/datasource/auth_remote_datasource.dart'; -import 'package:auth/src/core/data/mappers/user_model_mapper.dart'; import 'package:auth/src/core/data/models/child_profile_response_model.dart'; -import 'package:auth/src/core/data/models/payment_profile_response_model.dart'; import 'package:auth/src/core/data/models/sign_up_request_model.dart'; import 'package:auth/src/core/data/models/sign_up_response_model.dart'; import 'package:auth/src/core/data/models/two_fa_secret_response_model.dart'; import 'package:auth/src/core/domain/repositories/auth_repository.dart'; import 'package:auth/src/features/device_setup/domain/entities/child_profile_entity.dart'; import 'package:auth/src/features/login/domain/entities/login_response_entity.dart'; -import 'package:auth/src/features/login/domain/entities/payment_profile_entity.dart'; -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; import 'package:auth/src/features/sign_up/domain/entities/sign_up_request_entity.dart'; import 'package:auth/src/features/sign_up/domain/entities/sign_up_response_entity.dart'; import 'package:auth/src/core/data/models/login_response_model.dart'; @@ -60,25 +56,11 @@ class AuthRepositoryImpl implements AuthRepository { ); } - @override - Future getUserInfo() async { - final model = await _remote.getUserInfo(); - return model.toEntity(); - } - @override Future createWallet() { return _remote.createWallet(); } - @override - Future getPaymentProfile({ - required String userId, - }) async { - final model = await _remote.getPaymentProfile(userId: userId); - return model.toEntity(); - } - // @override // Future totpLogin({required String token, required String code}) { // return _remote.totpLogin(token: token, code: code); diff --git a/modules/auth/lib/src/core/domain/repositories/auth_repository.dart b/modules/auth/lib/src/core/domain/repositories/auth_repository.dart index 0041a5ad..9d26844b 100644 --- a/modules/auth/lib/src/core/domain/repositories/auth_repository.dart +++ b/modules/auth/lib/src/core/domain/repositories/auth_repository.dart @@ -1,9 +1,6 @@ -import 'package:auth/src/core/data/models/child_profile_response_model.dart'; import 'package:auth/src/core/data/models/two_fa_secret_response_model.dart'; import 'package:auth/src/features/device_setup/domain/entities/child_profile_entity.dart'; import 'package:auth/src/features/login/domain/entities/login_response_entity.dart'; -import 'package:auth/src/features/login/domain/entities/payment_profile_entity.dart'; -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; import 'package:auth/src/features/sign_up/domain/entities/sign_up_request_entity.dart'; import 'package:auth/src/features/sign_up/domain/entities/sign_up_response_entity.dart'; @@ -25,12 +22,9 @@ abstract class AuthRepository { required String code, required String methodType, }); - Future getUserInfo(); Future createWallet(); - Future getPaymentProfile({required String userId}); - // Future totpLogin({required String token, required String code}); Future signUp({required SignUpRequestEntity request}); diff --git a/modules/auth/lib/src/features/device_setup/presentation/state/device_setup_view_model.dart b/modules/auth/lib/src/features/device_setup/presentation/state/device_setup_view_model.dart index a7a966c0..03eab7a9 100644 --- a/modules/auth/lib/src/features/device_setup/presentation/state/device_setup_view_model.dart +++ b/modules/auth/lib/src/features/device_setup/presentation/state/device_setup_view_model.dart @@ -5,14 +5,12 @@ import 'package:auth/src/features/device_setup/presentation/enums/scan_link_step import 'package:auth/src/features/device_setup/presentation/providers/create_child_profile_use_case_provider.dart'; import 'package:auth/src/features/device_setup/presentation/state/device_setup_view_state.dart'; import 'package:auth/src/features/device_setup/presentation/enums/add_kid_step.dart'; -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; -import 'package:auth/src/features/login/domain/get_me_user_use_case.dart'; -import 'package:auth/src/features/login/presentation/providers/get_user_info_provider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get_it/get_it.dart'; import 'package:sca_treezor/sca_treezor.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:sf_shared/sf_shared.dart'; import 'package:uuid/uuid.dart'; final deviceSetupViewModelProvider = @@ -80,9 +78,7 @@ class DeviceSetupViewModel extends Notifier { case AddKidStep.scanStrap: final hasStrap = state.strapQr.isNotEmpty || state.strapCode.isNotEmpty; if (!hasStrap) { - state = state.copyWith( - errorMessage: I18n.errorScanStrapRequired, - ); + state = state.copyWith(errorMessage: I18n.errorScanStrapRequired); return; } state = state.copyWith(step: AddKidStep.scanWatch, errorMessage: ''); @@ -90,9 +86,7 @@ class DeviceSetupViewModel extends Notifier { case AddKidStep.scanWatch: final hasWatch = state.watchQr.isNotEmpty || state.watchCode.isNotEmpty; if (!hasWatch) { - state = state.copyWith( - errorMessage: I18n.errorScanWatchRequired, - ); + state = state.copyWith(errorMessage: I18n.errorScanWatchRequired); return; } state = state.copyWith(step: AddKidStep.profile, errorMessage: ''); diff --git a/modules/auth/lib/src/features/login/domain/get_me_user_use_case_impl.dart b/modules/auth/lib/src/features/login/domain/get_me_user_use_case_impl.dart deleted file mode 100644 index f827266e..00000000 --- a/modules/auth/lib/src/features/login/domain/get_me_user_use_case_impl.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:auth/src/core/domain/repositories/auth_repository.dart'; -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; -import 'package:auth/src/features/login/domain/get_me_user_use_case.dart'; - -class GetUserInfoUseCaseImpl implements GetUserInfoUseCase { - GetUserInfoUseCaseImpl(this._repository); - - final AuthRepository _repository; - - @override - Future getUserInfo() { - return _repository.getUserInfo(); - } -} diff --git a/modules/auth/lib/src/features/login/presentation/providers/get_user_info_provider.dart b/modules/auth/lib/src/features/login/presentation/providers/get_user_info_provider.dart deleted file mode 100644 index 83696f4e..00000000 --- a/modules/auth/lib/src/features/login/presentation/providers/get_user_info_provider.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:auth/src/core/providers/auth_repository_provider.dart'; -import 'package:auth/src/features/login/domain/get_me_user_use_case.dart'; -import 'package:auth/src/features/login/domain/get_me_user_use_case_impl.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final getUserInfoUseCaseProvider = Provider.autoDispose(( - ref, -) { - final authRepository = ref.read(authRepositoryProvider); - return GetUserInfoUseCaseImpl(authRepository); -}); diff --git a/modules/auth/lib/src/features/login/presentation/state/login_view_model.dart b/modules/auth/lib/src/features/login/presentation/state/login_view_model.dart index 3ba393bc..624c58f1 100644 --- a/modules/auth/lib/src/features/login/presentation/state/login_view_model.dart +++ b/modules/auth/lib/src/features/login/presentation/state/login_view_model.dart @@ -1,9 +1,6 @@ -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; -import 'package:auth/src/features/login/domain/get_me_user_use_case.dart'; import 'package:auth/src/features/login/domain/login_use_case.dart'; import 'package:auth/src/features/login/domain/two_fa_request_code_use_case.dart'; import 'package:auth/src/features/login/domain/two_fa_send_code_use_case.dart'; -import 'package:auth/src/features/login/presentation/providers/get_user_info_provider.dart'; import 'package:auth/src/features/login/presentation/providers/login_provider.dart'; import 'package:auth/src/features/login/presentation/providers/two_fa_request_code_provider.dart'; import 'package:auth/src/features/login/presentation/providers/two_fa_send_code_provider.dart'; @@ -11,6 +8,7 @@ import 'package:auth/src/features/login/presentation/state/login_view_state.dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:sf_shared/sf_shared.dart'; final loginViewModelProvider = NotifierProvider.autoDispose( diff --git a/modules/auth/lib/src/features/sca_treezor/sca_treezor_view_model.dart b/modules/auth/lib/src/features/sca_treezor/sca_treezor_view_model.dart index c4f4f390..b282b555 100644 --- a/modules/auth/lib/src/features/sca_treezor/sca_treezor_view_model.dart +++ b/modules/auth/lib/src/features/sca_treezor/sca_treezor_view_model.dart @@ -32,6 +32,8 @@ class SCATreezorViewModel extends Notifier { late final TreezorWalletConnectionService _connectionService; late final TreezorWalletSignatureService _signatureService; late final AuthRepository _authRepository; + late final GetPaymentProfileUseCase _getPaymentProfileUseCase; + late final GetUserInfoUseCase _getUserInfoUseCase; late final SessionLocalDatasource _sessionLocal; late final TextEditingController codeController; @@ -52,6 +54,8 @@ class SCATreezorViewModel extends Notifier { _connectionService = GetIt.I(); _signatureService = GetIt.I(); _authRepository = ref.read(authRepositoryProvider); + _getPaymentProfileUseCase = ref.read(getPaymentProfileUseCaseProvider); + _getUserInfoUseCase = ref.read(getUserInfoUseCaseProvider); _sessionLocal = ref.read(sessionLocalDatasourceProvider); codeController = TextEditingController(); codeController.addListener(_onCodeChanged); @@ -317,8 +321,8 @@ class SCATreezorViewModel extends Notifier { if (!connected) return false; await signJwtSca(); - final user = await _authRepository.getUserInfo(); - final paymentProfile = await _authRepository.getPaymentProfile( + final user = await _getUserInfoUseCase.getUserInfo(); + final paymentProfile = await _getPaymentProfileUseCase.getPaymentProfile( userId: user.id, ); debugPrint( @@ -328,6 +332,7 @@ class SCATreezorViewModel extends Notifier { if (paymentProfile.paymentWalletId == null || paymentProfile.paymentWalletId!.isEmpty) { await _authRepository.createWallet(); + // tengo que coger la walletId de createWallet y pasarlo savePaymentProfileId await _sessionLocal.savePaymentProfileId(paymentProfile.paymentWalletId!); } // remove this when the backend starts returning the walletId on getUserInfo or getPaymentProfile diff --git a/modules/home/lib/src/presentation/home_screen.dart b/modules/home/lib/src/presentation/home_screen.dart index 7897353f..9879660b 100644 --- a/modules/home/lib/src/presentation/home_screen.dart +++ b/modules/home/lib/src/presentation/home_screen.dart @@ -7,7 +7,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:navigation/navigation.dart'; class HomeScreen extends ConsumerWidget { - final String name = "Juan"; final double total = 95.03; final List kids = [ Kid(name: "Carlos", balance: 25.47, savings: 8.32), @@ -26,6 +25,11 @@ class HomeScreen extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final theme = ref.watch(themePortProvider); final NavigationContract navigationContract = GetIt.I(); + final user = ref.watch(userInfoProvider); + final rawName = user.value?.firstName ?? ""; + final name = rawName.isEmpty + ? "" + : rawName[0].toUpperCase() + rawName.substring(1).toLowerCase(); return SafeArea( child: SingleChildScrollView( diff --git a/modules/profile/lib/profile.dart b/modules/profile/lib/profile.dart index 357976e9..2c5f0296 100644 --- a/modules/profile/lib/profile.dart +++ b/modules/profile/lib/profile.dart @@ -1,2 +1,3 @@ export 'src/presentation/profile_screen.dart'; export 'src/profile_builder.dart'; +export 'src/profile_settings_builder.dart'; diff --git a/modules/profile/lib/src/core/kid_line_chart.dart b/modules/profile/lib/src/core/kid_line_chart.dart index d6eaf940..e3cc2f14 100644 --- a/modules/profile/lib/src/core/kid_line_chart.dart +++ b/modules/profile/lib/src/core/kid_line_chart.dart @@ -80,17 +80,15 @@ class KidLineChart extends ConsumerWidget{ return SideTitleWidget( space: 4, meta: meta, - child: Expanded( - child: Center( - child: Text( - text, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: theme.getColorFor(ThemeCode.textSecondary) - ) - ) - ) + child: Center( + child: Text( + text, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: theme.getColorFor(ThemeCode.textSecondary), + ), + ), ), ); }, diff --git a/modules/profile/lib/src/presentation/profile_screen.dart b/modules/profile/lib/src/presentation/profile_screen.dart index 6f86ac46..84bcd9ae 100644 --- a/modules/profile/lib/src/presentation/profile_screen.dart +++ b/modules/profile/lib/src/presentation/profile_screen.dart @@ -1,13 +1,15 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; +import 'package:navigation/navigation.dart'; import 'package:notifications/notifications.dart'; import 'package:profile/src/core/kid_line_chart.dart'; -import 'package:profile/src/settings_screen.dart'; import 'package:sf_shared/sf_shared.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class ProfileScreen extends ConsumerWidget { - const ProfileScreen({super.key}); + final NavigationContract navigationContract; + + const ProfileScreen({super.key, required this.navigationContract}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -22,10 +24,14 @@ class ProfileScreen extends ConsumerWidget { final kids = [ Kid(name: "Ana", balance: 15, savings: 5), - Kid(name: "Carlos", balance: 15, savings: 5) + Kid(name: "Carlos", balance: 15, savings: 5), ]; - final name = "Juan"; + final user = ref.watch(userInfoProvider); + final rawName = user.value?.firstName ?? ""; + final name = rawName.isEmpty + ? "" + : rawName[0].toUpperCase() + rawName.substring(1).toLowerCase(); final total = 95.03; final available = 44.09; final savings = 4.16; @@ -44,10 +50,8 @@ class ProfileScreen extends ConsumerWidget { ), Spacer(), TextButton( - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (_) => SettingsScreen()), - ), + onPressed: () => + navigationContract.pushTo(AppRoutes.dashboardProfileSettings), child: Text( "Ajustes de la cuenta", style: TextStyle( @@ -57,7 +61,12 @@ class ProfileScreen extends ConsumerWidget { ), ], ), - WalletBalanceBlock(max: total, value: available, savings: savings, savingsPlan: savingsPlan), + WalletBalanceBlock( + max: total, + value: available, + savings: savings, + savingsPlan: savingsPlan, + ), LineGraph(), DepositBlock(max: 150 - total), Container( @@ -67,33 +76,34 @@ class ProfileScreen extends ConsumerWidget { color: theme.getColorFor(ThemeCode.backgroundPrimary), ), child: TextButton( - onPressed: ()=>{}, + onPressed: () => {}, child: Row( spacing: 10, children: [ - Icon(Icons.output_outlined, + Icon( + Icons.output_outlined, size: 24, - color: theme.getColorFor(ThemeCode.textPrimary) + color: theme.getColorFor(ThemeCode.textPrimary), ), Text( "Retirar dinero del wallet", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500, - color: theme.getColorFor(ThemeCode.textPrimary) - ) - ) + color: theme.getColorFor(ThemeCode.textPrimary), + ), + ), ], - ) - ) + ), + ), ), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( spacing: 16, - children: List.generate(kids.length, (int index){ + children: List.generate(kids.length, (int index) { return KidLineChart(kid: kids[index], index: index); - }) + }), ), ), ActivityList(activity: activity, edit: false), @@ -105,7 +115,10 @@ class ProfileScreen extends ConsumerWidget { children: [ DecoratedBox( decoration: BoxDecoration( - borderRadius: const BorderRadius.only(bottomRight: Radius.circular(24), bottomLeft: Radius.circular(24)), + borderRadius: const BorderRadius.only( + bottomRight: Radius.circular(24), + bottomLeft: Radius.circular(24), + ), color: Color(0xFF4B4B4B), ), child: SizedBox(width: double.infinity, height: 200), diff --git a/modules/profile/lib/src/settings_screen.dart b/modules/profile/lib/src/presentation/profile_settings_screen.dart similarity index 55% rename from modules/profile/lib/src/settings_screen.dart rename to modules/profile/lib/src/presentation/profile_settings_screen.dart index dfe1c93a..c1380930 100644 --- a/modules/profile/lib/src/settings_screen.dart +++ b/modules/profile/lib/src/presentation/profile_settings_screen.dart @@ -1,24 +1,79 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:navigation/navigation.dart'; +import 'package:sealed_countries/sealed_countries.dart'; +import '../providers/payment_profile_provider.dart'; -class SettingsScreen extends ConsumerWidget { - const SettingsScreen({super.key}); +class ProfileSettingsScreen extends ConsumerWidget { + final NavigationContract navigationContract; + + const ProfileSettingsScreen({super.key, required this.navigationContract}); @override Widget build(BuildContext context, WidgetRef ref) { final theme = ref.watch(themePortProvider); + final user = ref.watch(profileSettingsDataProvider); - final name = "Juan"; - final balance = 50; - final fullName = "Juan Pérez Cruz"; - final birthDate = "08/03/1976"; - final relation = "Padre"; - final address = "Calle Gran Vía 30 6º, 28013"; - final country = "España"; - final nationality = "Español"; - final email = "juanpcruz@gmail.com"; - final phone = "123456789"; + return Scaffold( + backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary), + body: user.when( + loading: () => Center(child: CircularProgressIndicator()), + error: (error, _) => Center( + child: Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Error al cargar el perfil", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: theme.getColorFor(ThemeCode.textPrimary), + ), + ), + SizedBox(height: 8), + Text( + error.toString(), + textAlign: TextAlign.center, + style: TextStyle( + color: theme.getColorFor(ThemeCode.textPrimary), + ), + ), + SizedBox(height: 16), + TextButton( + onPressed: () => ref.invalidate(profileSettingsDataProvider), + child: Text("Reintentar"), + ), + ], + ), + ), + ), + data: (data) => _buildContent(context, ref, theme, data), + ), + ); + } + + Widget _buildContent( + BuildContext context, + WidgetRef ref, + ThemePort theme, + ProfileSettingsData data, + ) { + final profile = data.paymentProfile; + final firstName = _capitalize(data.user.firstName); + final lastName = _capitalize(data.user.lastName); + final fullName = '$firstName $lastName'; + final birthDate = _formatTimestamp(profile.bornAt); + final address = profile.addresses.isNotEmpty + ? '${profile.addresses.first.street}, ${profile.addresses.first.postCode} ${profile.addresses.first.city}' + : '-'; + final country = profile.addresses.isNotEmpty + ? profile.addresses.first.country + : profile.birthCountry; + final locale = Localizations.localeOf(context).languageCode; + final nationality = _countryNameFromCode(profile.nationality, locale); final content = [ Center( @@ -31,12 +86,6 @@ class SettingsScreen extends ConsumerWidget { color: theme.getColorFor(ThemeCode.textSecondary), ), ), - Text( - "Saldo: $balance€", - style: TextStyle( - color: theme.getColorFor(ThemeCode.textSecondary), - ), - ), ], ), ), @@ -52,7 +101,7 @@ class SettingsScreen extends ConsumerWidget { spacing: 10, children: [ Text( - name, + firstName, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), ), Spacer(), @@ -60,7 +109,15 @@ class SettingsScreen extends ConsumerWidget { Icon(Icons.account_balance, size: 24), ], ), - Align(alignment: Alignment.centerLeft, child: Text(relation)), + Align( + alignment: Alignment.centerLeft, + child: Text( + data.user.status.toUpperCase(), + style: TextStyle( + color: theme.getColorFor(ThemeCode.textPrimary), + ), + ), + ), ], ), ), @@ -82,50 +139,13 @@ class SettingsScreen extends ConsumerWidget { TextButton(onPressed: () => {}, child: Text("Editar")), ], ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Nombre: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: fullName, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ) - ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Fecha de nacimiento: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: birthDate, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ) - ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Familiar: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: relation, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ) + _labelValue("Nombre", fullName), + _labelValue("Fecha de nacimiento", birthDate), + _labelValue("Nacionalidad", nationality), + _labelValue("Lugar de nacimiento", profile.placeOfBirth), + _labelValue( + "Documento (${profile.documentType})", + profile.document.toUpperCase(), ), ], ), @@ -148,51 +168,9 @@ class SettingsScreen extends ConsumerWidget { TextButton(onPressed: () => {}, child: Text("Editar")), ], ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Dirección: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: address, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ), - ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "País: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: country, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ), - ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Nacionalidad: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: nationality, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ), - ) + _labelValue("Dirección", address), + _labelValue("País", country), + _labelValue("Nacionalidad", nationality), ], ), ), @@ -214,36 +192,8 @@ class SettingsScreen extends ConsumerWidget { TextButton(onPressed: () => {}, child: Text("Editar")), ], ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Correo: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: email, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ), - ), - Align( - alignment: Alignment.centerLeft, - child: Text.rich( - TextSpan( - text: "Teléfono: ", - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: phone, - style: TextStyle(fontWeight: FontWeight.normal), - ), - ], - ), - ), - ) + _labelValue("Correo", data.user.email), + _labelValue("Teléfono", profile.phone), ], ), ), @@ -299,9 +249,11 @@ class SettingsScreen extends ConsumerWidget { "Retirar y reembolsar dinero del wallet", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), ), - Text("Para transferirte el saldo a tu cuenta necesitamos tu IBAN y algunos datos básics. Así nos aseguramos de que la transferencia sea segura y rápida."), + Text( + "Para transferirte el saldo a tu cuenta necesitamos tu IBAN y algunos datos básics. Así nos aseguramos de que la transferencia sea segura y rápida.", + ), CustomTextField(label: "Nombre y Apellidos", hint: "******"), - CustomTextField(label: "IBAN con número español", hint: "******") + CustomTextField(label: "IBAN con número español", hint: "******"), ], ), ), @@ -334,7 +286,7 @@ class SettingsScreen extends ConsumerWidget { style: TextStyle(fontSize: 16, letterSpacing: 0), ), ], - ) + ), ), Align( alignment: Alignment.centerLeft, @@ -347,7 +299,7 @@ class SettingsScreen extends ConsumerWidget { style: TextStyle(fontSize: 16, letterSpacing: 0), ), ], - ) + ), ), Align( alignment: Alignment.centerLeft, @@ -360,7 +312,7 @@ class SettingsScreen extends ConsumerWidget { style: TextStyle(fontSize: 16, letterSpacing: 0), ), ], - ) + ), ), ], ), @@ -371,89 +323,130 @@ class SettingsScreen extends ConsumerWidget { Align( alignment: Alignment.topLeft, child: TextButton( - style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))), + style: ButtonStyle( + padding: WidgetStatePropertyAll(EdgeInsets.all(0)), + ), onPressed: () => {}, child: Row( spacing: 4, children: [ Icon(Icons.contact_support_outlined, size: 24), - Text("Contáctanos") + Text("Contáctanos"), ], - ) - ) + ), + ), ), Align( alignment: Alignment.topLeft, child: TextButton( - style: ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(0))), + style: ButtonStyle( + padding: WidgetStatePropertyAll(EdgeInsets.all(0)), + ), onPressed: () => {}, child: Row( spacing: 4, children: [ Icon(Icons.contact_support_outlined, size: 24), - Text("Preguntas frecuentes") + Text("Preguntas frecuentes"), ], - ) - ) - ), - ], - ) - ]; - - return Scaffold( - backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary), - body: Stack( - children: [ - DecoratedBox( - decoration: BoxDecoration( - borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), - color: Color(0xFF4B4B4B), + ), ), - child: SizedBox(width: double.infinity, height: 200), - ), - Column( - children: [ - Expanded( - child: Container( - margin: EdgeInsets.all(20), - child: ListView.separated( - itemBuilder: (BuildContext context, int index) { - return content[index]; - }, - separatorBuilder: (BuildContext context, int index) { - return Divider(color: Colors.transparent, height: 20); - }, - itemCount: content.length, - ), - ), - ), - Container( - padding: EdgeInsets.all(20), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - color: theme.getColorFor(ThemeCode.backgroundPrimary), - ), - child: Column( - children: [ - PrimaryButton( - onPressed: () => {}, - text: "Guardar cambios", - color: theme.getColorFor(ThemeCode.buttonPrimary) - ), - TextButton( - onPressed: () => Navigator.pop(context), - child: Text("Cancelar"), - ), - ], - ), - ), - ], ), ], ), + ]; + + return Stack( + children: [ + DecoratedBox( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24), + ), + color: Color(0xFF4B4B4B), + ), + child: SizedBox(width: double.infinity, height: 200), + ), + Column( + children: [ + Expanded( + child: Container( + margin: EdgeInsets.all(20), + child: ListView.separated( + itemBuilder: (BuildContext context, int index) { + return content[index]; + }, + separatorBuilder: (BuildContext context, int index) { + return Divider(color: Colors.transparent, height: 20); + }, + itemCount: content.length, + ), + ), + ), + Container( + padding: EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + color: theme.getColorFor(ThemeCode.backgroundPrimary), + ), + child: Column( + children: [ + PrimaryButton( + onPressed: () => {}, + text: "Guardar cambios", + color: theme.getColorFor(ThemeCode.buttonPrimary), + ), + TextButton( + onPressed: () => navigationContract.goBack(), + child: Text("Cancelar"), + ), + ], + ), + ), + ], + ), + ], ); } + + Widget _labelValue(String label, String value) { + return Align( + alignment: Alignment.centerLeft, + child: Text.rich( + TextSpan( + text: "$label: ", + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: value, + style: TextStyle(fontWeight: FontWeight.normal), + ), + ], + ), + ), + ); + } + + String _capitalize(String s) => + s.isEmpty ? s : s[0].toUpperCase() + s.substring(1).toLowerCase(); + + String _countryNameFromCode(String code, String locale) { + if (code.isEmpty) return '-'; + try { + final country = WorldCountry.fromCodeShort(code.toUpperCase()); + final language = NaturalLanguage.fromCodeShort(locale); + return country.commonNameFor(BasicTypedLocale(language)); + } catch (_) { + return code; + } + } + + String _formatTimestamp(int timestamp) { + final date = DateTime.fromMillisecondsSinceEpoch(timestamp); + return '${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}'; + } } diff --git a/modules/profile/lib/src/profile_builder.dart b/modules/profile/lib/src/profile_builder.dart index 27308ff0..08c37eb4 100644 --- a/modules/profile/lib/src/profile_builder.dart +++ b/modules/profile/lib/src/profile_builder.dart @@ -1,11 +1,17 @@ import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; +import 'package:navigation/navigation.dart'; import 'package:profile/profile.dart'; class ProfileBuilder { const ProfileBuilder(); Page buildPage(BuildContext context, GoRouterState state) { - return MaterialPage(child: ProfileScreen()); + final navigationContract = GetIt.I(); + return MaterialPage( + key: state.pageKey, + child: ProfileScreen(navigationContract: navigationContract), + ); } } diff --git a/modules/profile/lib/src/profile_settings_builder.dart b/modules/profile/lib/src/profile_settings_builder.dart new file mode 100644 index 00000000..24c08c70 --- /dev/null +++ b/modules/profile/lib/src/profile_settings_builder.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:go_router/go_router.dart'; +import 'package:navigation/navigation.dart'; +import 'package:profile/src/presentation/profile_settings_screen.dart'; + +class ProfileSettingsBuilder { + const ProfileSettingsBuilder(); + + Page buildPage(BuildContext context, GoRouterState state) { + final navigationContract = GetIt.I(); + return MaterialPage( + key: state.pageKey, + child: ProfileSettingsScreen(navigationContract: navigationContract), + ); + } +} diff --git a/modules/profile/lib/src/providers/payment_profile_provider.dart b/modules/profile/lib/src/providers/payment_profile_provider.dart new file mode 100644 index 00000000..b900f975 --- /dev/null +++ b/modules/profile/lib/src/providers/payment_profile_provider.dart @@ -0,0 +1,27 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:sf_shared/sf_shared.dart'; + +class ProfileSettingsData { + final UserEntity user; + final PaymentProfileEntity paymentProfile; + + const ProfileSettingsData({ + required this.user, + required this.paymentProfile, + }); +} + +final profileSettingsDataProvider = + FutureProvider.autoDispose((ref) async { + final getUserInfoUseCase = ref.read(getUserInfoUseCaseProvider); + final getPaymentProfileUseCase = ref.read(getPaymentProfileUseCaseProvider); + + final user = await getUserInfoUseCase.getUserInfo(); + final paymentProfile = + await getPaymentProfileUseCase.getPaymentProfile(userId: user.id); + + return ProfileSettingsData( + user: user, + paymentProfile: paymentProfile, + ); +}); diff --git a/modules/profile/pubspec.yaml b/modules/profile/pubspec.yaml index 55d1a18f..f3ee2b65 100644 --- a/modules/profile/pubspec.yaml +++ b/modules/profile/pubspec.yaml @@ -20,8 +20,11 @@ dependencies: path: ../../packages/design_system sf_shared: path: ../../packages/sf_shared + navigation: + path: ../../packages/navigation #dependencies go here + sealed_countries: ^2.8.0 flutter_riverpod: ^3.0.3 get_it: ^9.0.5 go_router: ^17.0.0 diff --git a/modules/profile/pubspec_overrides.yaml b/modules/profile/pubspec_overrides.yaml index f51621da..ef92deb6 100644 --- a/modules/profile/pubspec_overrides.yaml +++ b/modules/profile/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: design_system,notifications,sf_shared,utils,fonts,sf_infrastructure,flutter_treezor_entrust_sdk_bridge,sca_treezor +# melos_managed_dependency_overrides: design_system,notifications,sf_shared,utils,fonts,sf_infrastructure,flutter_treezor_entrust_sdk_bridge,sca_treezor,navigation dependency_overrides: design_system: path: ../../packages/design_system @@ -6,6 +6,8 @@ dependency_overrides: path: ../../packages/flutter_treezor_entrust_sdk_bridge fonts: path: ../../packages/fonts + navigation: + path: ../../packages/navigation notifications: path: ../notifications sca_treezor: diff --git a/modules/splash/lib/src/data/splash_remote_datasource.dart b/modules/splash/lib/src/data/splash_remote_datasource.dart deleted file mode 100644 index 11edec49..00000000 --- a/modules/splash/lib/src/data/splash_remote_datasource.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class SplashRemoteDatasource { - Future> getChildProfiles(); -} diff --git a/modules/splash/lib/src/data/splash_remote_datasource_impl.dart b/modules/splash/lib/src/data/splash_remote_datasource_impl.dart deleted file mode 100644 index 8157af77..00000000 --- a/modules/splash/lib/src/data/splash_remote_datasource_impl.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:sf_infrastructure/sf_infrastructure.dart'; - -import 'splash_remote_datasource.dart'; - -class SplashRemoteDatasourceImpl implements SplashRemoteDatasource { - SplashRemoteDatasourceImpl(this._repository); - - final QuestiaRepository _repository; - - @override - Future> getChildProfiles() async { - final response = - await _repository.get>('/child-profiles'); - final data = response.data; - if (data == null) return []; - final items = data['items'] ?? data['data'] ?? []; - return items is List ? items : []; - } -} diff --git a/modules/splash/lib/src/domain/check_session_use_case_impl.dart b/modules/splash/lib/src/domain/check_session_use_case_impl.dart index 4aea4666..513ac0d2 100644 --- a/modules/splash/lib/src/domain/check_session_use_case_impl.dart +++ b/modules/splash/lib/src/domain/check_session_use_case_impl.dart @@ -1,18 +1,18 @@ import 'package:flutter/material.dart'; +import 'package:sf_shared/sf_shared.dart'; -import '../data/splash_remote_datasource.dart'; import 'check_session_use_case.dart'; import 'initial_route.dart'; class CheckSessionUseCaseImpl implements CheckSessionUseCase { - CheckSessionUseCaseImpl(this._datasource); + CheckSessionUseCaseImpl(this._userRepository); - final SplashRemoteDatasource _datasource; + final UserRepository _userRepository; @override Future execute() async { try { - final profiles = await _datasource.getChildProfiles(); + final profiles = await _userRepository.getChildProfiles(); return profiles.isEmpty ? InitialRoute.deviceSetup : InitialRoute.home; } catch (e) { debugPrint('[CheckSessionUseCase] error: $e'); diff --git a/modules/splash/lib/src/splash_builder.dart b/modules/splash/lib/src/splash_builder.dart index 01fe1d22..49d6b38a 100644 --- a/modules/splash/lib/src/splash_builder.dart +++ b/modules/splash/lib/src/splash_builder.dart @@ -3,7 +3,7 @@ import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; import 'package:navigation/navigation_contract.dart'; import 'package:sf_infrastructure/sf_infrastructure.dart'; -import 'package:splash/src/data/splash_remote_datasource_impl.dart'; +import 'package:sf_shared/sf_shared.dart'; import 'package:splash/src/domain/check_session_use_case_impl.dart'; import 'package:splash/src/presentation/splash_screen.dart'; @@ -12,8 +12,9 @@ class SplashBuilder { Page buildPage(BuildContext context, GoRouterState state) { final navigationContract = GetIt.I(); - final datasource = SplashRemoteDatasourceImpl(GetIt.I()); - final checkSessionUseCase = CheckSessionUseCaseImpl(datasource); + final remote = UserRemoteDatasourceImpl(GetIt.I()); + final userRepository = UserRepositoryImpl(remote); + final checkSessionUseCase = CheckSessionUseCaseImpl(userRepository); return NoTransitionPage( child: SplashScreen( diff --git a/modules/splash/pubspec.yaml b/modules/splash/pubspec.yaml index ad2d1da7..1cd8a56a 100644 --- a/modules/splash/pubspec.yaml +++ b/modules/splash/pubspec.yaml @@ -19,6 +19,8 @@ dependencies: path: ../../packages/navigation sf_infrastructure: path: ../../packages/sf_infrastructure + sf_shared: + path: ../../packages/sf_shared dev_dependencies: flutter_test: sdk: flutter diff --git a/modules/splash/pubspec_overrides.yaml b/modules/splash/pubspec_overrides.yaml index a4176d2b..c7512769 100644 --- a/modules/splash/pubspec_overrides.yaml +++ b/modules/splash/pubspec_overrides.yaml @@ -1,4 +1,18 @@ -# melos_managed_dependency_overrides: navigation +# melos_managed_dependency_overrides: navigation,sf_infrastructure,design_system,flutter_treezor_entrust_sdk_bridge,fonts,sca_treezor,sf_shared,utils dependency_overrides: + design_system: + path: ../../packages/design_system + flutter_treezor_entrust_sdk_bridge: + path: ../../packages/flutter_treezor_entrust_sdk_bridge + fonts: + path: ../../packages/fonts navigation: path: ../../packages/navigation + sca_treezor: + path: ../../packages/sca_treezor + sf_infrastructure: + path: ../../packages/sf_infrastructure + sf_shared: + path: ../../packages/sf_shared + utils: + path: ../../packages/utils diff --git a/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml b/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml index c6999cf5..a6a9e0c0 100644 --- a/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml +++ b/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml @@ -7,6 +7,6 @@ 2.6.4 - 20260210000000 + 20260212000000 diff --git a/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.md5 b/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.md5 index 4cf0bb31..8015d114 100644 --- a/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.md5 +++ b/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.md5 @@ -1 +1 @@ -d77d08495d6aeaec19114b634957c84c \ No newline at end of file +299dd618be3c19b3aced93d75bb14a01 \ No newline at end of file diff --git a/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.sha1 b/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.sha1 index dca21762..803fcbc1 100644 --- a/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.sha1 +++ b/packages/flutter_treezor_entrust_sdk_bridge/android/build/com/entrust/antelop/antelop/maven-metadata.xml.sha1 @@ -1 +1 @@ -bdcbc45dfb9b2a6ccb485f2e1114aeef96a11ce7 \ No newline at end of file +9967947368e66f19dfcef5b3d016f0fdfd89f20e \ No newline at end of file diff --git a/packages/navigation/lib/app_routes.dart b/packages/navigation/lib/app_routes.dart index 8e421dd8..02466b86 100644 --- a/packages/navigation/lib/app_routes.dart +++ b/packages/navigation/lib/app_routes.dart @@ -15,4 +15,5 @@ class AppRoutes { static const dashboardActivity = '$dashboard/activity'; static const dashboardNotifications = '$dashboard/notifications'; static const dashboardProfile = '$dashboard/profile'; + static const dashboardProfileSettings = '$dashboardProfile/settings'; } diff --git a/packages/sf_shared/lib/sf_shared.dart b/packages/sf_shared/lib/sf_shared.dart index 627fdd30..816f4c62 100644 --- a/packages/sf_shared/lib/sf_shared.dart +++ b/packages/sf_shared/lib/sf_shared.dart @@ -13,3 +13,14 @@ export 'src/domain/entities/sca_wallet_entity.dart'; export 'src/domain/use_cases/sca_wallets_use_case.dart'; export 'src/domain/use_cases/send_jws_sesion_use_case.dart'; export 'src/providers/send_jws_sesion_use_case_provider.dart'; +export 'src/domain/entities/payment_profile_entity.dart'; +export 'src/domain/use_cases/get_payment_profile_use_case.dart'; +export 'src/providers/get_payment_profile_use_case_provider.dart'; +export 'src/domain/entities/child_profile_entity.dart'; +export 'src/domain/entities/user_entity.dart'; +export 'src/domain/use_cases/get_user_info_use_case.dart'; +export 'src/providers/get_user_info_use_case_provider.dart'; +export 'src/providers/user_info_provider.dart'; +export 'src/domain/repositories/user_repository.dart'; +export 'src/data/repositories/user_repository_impl.dart'; +export 'src/data/datasource/user_remote_datasource_impl.dart'; diff --git a/packages/sf_shared/lib/src/data/datasource/treezor_remote_data_source.dart b/packages/sf_shared/lib/src/data/datasource/treezor_remote_data_source.dart index a4fc80ea..9841e3ff 100644 --- a/packages/sf_shared/lib/src/data/datasource/treezor_remote_data_source.dart +++ b/packages/sf_shared/lib/src/data/datasource/treezor_remote_data_source.dart @@ -1,7 +1,12 @@ +import 'package:sf_shared/src/data/models/payment_profile_response_model.dart'; import 'package:sf_shared/src/data/models/sca_wallet_model.dart'; abstract class TreezorRemoteDatasource { Future scaWallets(); Future sendJWSSesion({required String jws}); + + Future getPaymentProfile({ + required String userId, + }); } diff --git a/packages/sf_shared/lib/src/data/datasource/trezzor_remote_data_source_impl.dart b/packages/sf_shared/lib/src/data/datasource/trezzor_remote_data_source_impl.dart index b86c2f88..86840df3 100644 --- a/packages/sf_shared/lib/src/data/datasource/trezzor_remote_data_source_impl.dart +++ b/packages/sf_shared/lib/src/data/datasource/trezzor_remote_data_source_impl.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:sf_infrastructure/sf_infrastructure.dart'; +import 'package:sf_shared/src/data/models/payment_profile_response_model.dart'; import 'package:sf_shared/src/data/models/sca_wallet_model.dart'; import 'treezor_remote_data_source.dart'; @@ -61,6 +62,28 @@ class TreezorRemoteDatasourceImpl implements TreezorRemoteDatasource { ); } } + @override + Future getPaymentProfile({ + required String userId, + }) async { + try { + final response = await _repository.get>( + '/users/$userId/payment-profile', + ); + + final data = response.data; + if (data == null || data.isEmpty) { + throw Exception('Empty response from /users/$userId/payment-profile'); + } + + return PaymentProfileResponseModel.fromJson(data); + } on DioException catch (error) { + throw _mapDioError( + error, + defaultMessage: 'Error in /users/$userId/payment-profile', + ); + } + } } Exception _mapDioError(DioException error, {required String defaultMessage}) { diff --git a/packages/sf_shared/lib/src/data/datasource/user_remote_datasource.dart b/packages/sf_shared/lib/src/data/datasource/user_remote_datasource.dart new file mode 100644 index 00000000..c5d699d4 --- /dev/null +++ b/packages/sf_shared/lib/src/data/datasource/user_remote_datasource.dart @@ -0,0 +1,7 @@ +import 'package:sf_shared/src/data/models/child_profile_response_model.dart'; +import 'package:sf_shared/src/data/models/user_response_model.dart'; + +abstract class UserRemoteDatasource { + Future getUserInfo(); + Future getChildProfiles(); +} diff --git a/packages/sf_shared/lib/src/data/datasource/user_remote_datasource_impl.dart b/packages/sf_shared/lib/src/data/datasource/user_remote_datasource_impl.dart new file mode 100644 index 00000000..f9e9dcb0 --- /dev/null +++ b/packages/sf_shared/lib/src/data/datasource/user_remote_datasource_impl.dart @@ -0,0 +1,42 @@ +import 'package:dio/dio.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; +import 'package:sf_shared/src/data/models/child_profile_response_model.dart'; +import 'package:sf_shared/src/data/models/user_response_model.dart'; + +import 'user_remote_datasource.dart'; + +class UserRemoteDatasourceImpl implements UserRemoteDatasource { + UserRemoteDatasourceImpl(this._repository); + + final QuestiaRepository _repository; + + @override + Future getUserInfo() async { + try { + final response = await _repository.get>('/auth/me'); + + final data = response.data; + if (data == null || data.isEmpty) { + throw Exception('Empty response from /auth/me'); + } + + final parsed = UserResponseModel.fromJson(data); + return parsed.item; + } on DioException catch (error) { + final apiMsg = error.response?.data; + final msg = apiMsg is String ? apiMsg : (error.message ?? 'Error in /auth/me'); + throw Exception(msg); + } + } + + @override + Future getChildProfiles() async { + final response = + await _repository.get>('/child-profiles'); + final data = response.data; + if (data == null) { + throw Exception('Empty response from /child-profiles'); + } + return ChildProfileResponseModel.fromJson(data); + } +} diff --git a/packages/sf_shared/lib/src/data/models/child_profile_response_model.dart b/packages/sf_shared/lib/src/data/models/child_profile_response_model.dart new file mode 100644 index 00000000..014b7f61 --- /dev/null +++ b/packages/sf_shared/lib/src/data/models/child_profile_response_model.dart @@ -0,0 +1,54 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sf_shared/src/domain/entities/child_profile_entity.dart'; + +part 'child_profile_response_model.freezed.dart'; +part 'child_profile_response_model.g.dart'; + +@freezed +abstract class ChildProfileResponseModel with _$ChildProfileResponseModel { + const factory ChildProfileResponseModel({ + required int total, + required List items, + required int page, + required int pages, + }) = _ChildProfileResponseModel; + + factory ChildProfileResponseModel.fromJson(Map json) => + _$ChildProfileResponseModelFromJson(json); +} + +@freezed +abstract class ChildProfileModel with _$ChildProfileModel { + const factory ChildProfileModel({ + required String id, + required String deviceIdentificator, + required String parentId, + required String firstName, + required String lastName, + required int bornAt, + required String walletId, + required String treezorUserId, + required String address, + required int createdAt, + }) = _ChildProfileModel; + + factory ChildProfileModel.fromJson(Map json) => + _$ChildProfileModelFromJson(json); +} + +extension ChildProfileModelMapper on ChildProfileModel { + ChildProfileEntity toEntity() { + return ChildProfileEntity( + id: id, + deviceIdentificator: deviceIdentificator, + parentId: parentId, + firstName: firstName, + lastName: lastName, + bornAt: bornAt, + walletId: walletId, + treezorUserId: treezorUserId, + address: address, + createdAt: createdAt, + ); + } +} diff --git a/packages/sf_shared/lib/src/data/models/child_profile_response_model.freezed.dart b/packages/sf_shared/lib/src/data/models/child_profile_response_model.freezed.dart new file mode 100644 index 00000000..313019ff --- /dev/null +++ b/packages/sf_shared/lib/src/data/models/child_profile_response_model.freezed.dart @@ -0,0 +1,582 @@ +// 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 'child_profile_response_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$ChildProfileResponseModel { + + int get total; List get items; int get page; int get pages; +/// Create a copy of ChildProfileResponseModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ChildProfileResponseModelCopyWith get copyWith => _$ChildProfileResponseModelCopyWithImpl(this as ChildProfileResponseModel, _$identity); + + /// Serializes this ChildProfileResponseModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ChildProfileResponseModel&&(identical(other.total, total) || other.total == total)&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.page, page) || other.page == page)&&(identical(other.pages, pages) || other.pages == pages)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,total,const DeepCollectionEquality().hash(items),page,pages); + +@override +String toString() { + return 'ChildProfileResponseModel(total: $total, items: $items, page: $page, pages: $pages)'; +} + + +} + +/// @nodoc +abstract mixin class $ChildProfileResponseModelCopyWith<$Res> { + factory $ChildProfileResponseModelCopyWith(ChildProfileResponseModel value, $Res Function(ChildProfileResponseModel) _then) = _$ChildProfileResponseModelCopyWithImpl; +@useResult +$Res call({ + int total, List items, int page, int pages +}); + + + + +} +/// @nodoc +class _$ChildProfileResponseModelCopyWithImpl<$Res> + implements $ChildProfileResponseModelCopyWith<$Res> { + _$ChildProfileResponseModelCopyWithImpl(this._self, this._then); + + final ChildProfileResponseModel _self; + final $Res Function(ChildProfileResponseModel) _then; + +/// Create a copy of ChildProfileResponseModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? total = null,Object? items = null,Object? page = null,Object? pages = null,}) { + return _then(_self.copyWith( +total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable +as int,items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable +as List,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable +as int,pages: null == pages ? _self.pages : pages // ignore: cast_nullable_to_non_nullable +as int, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ChildProfileResponseModel]. +extension ChildProfileResponseModelPatterns on ChildProfileResponseModel { +/// 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( _ChildProfileResponseModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ChildProfileResponseModel() 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( _ChildProfileResponseModel value) $default,){ +final _that = this; +switch (_that) { +case _ChildProfileResponseModel(): +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( _ChildProfileResponseModel value)? $default,){ +final _that = this; +switch (_that) { +case _ChildProfileResponseModel() 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( int total, List items, int page, int pages)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ChildProfileResponseModel() when $default != null: +return $default(_that.total,_that.items,_that.page,_that.pages);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( int total, List items, int page, int pages) $default,) {final _that = this; +switch (_that) { +case _ChildProfileResponseModel(): +return $default(_that.total,_that.items,_that.page,_that.pages);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( int total, List items, int page, int pages)? $default,) {final _that = this; +switch (_that) { +case _ChildProfileResponseModel() when $default != null: +return $default(_that.total,_that.items,_that.page,_that.pages);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _ChildProfileResponseModel implements ChildProfileResponseModel { + const _ChildProfileResponseModel({required this.total, required final List items, required this.page, required this.pages}): _items = items; + factory _ChildProfileResponseModel.fromJson(Map json) => _$ChildProfileResponseModelFromJson(json); + +@override final int total; + final List _items; +@override List get items { + if (_items is EqualUnmodifiableListView) return _items; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_items); +} + +@override final int page; +@override final int pages; + +/// Create a copy of ChildProfileResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ChildProfileResponseModelCopyWith<_ChildProfileResponseModel> get copyWith => __$ChildProfileResponseModelCopyWithImpl<_ChildProfileResponseModel>(this, _$identity); + +@override +Map toJson() { + return _$ChildProfileResponseModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChildProfileResponseModel&&(identical(other.total, total) || other.total == total)&&const DeepCollectionEquality().equals(other._items, _items)&&(identical(other.page, page) || other.page == page)&&(identical(other.pages, pages) || other.pages == pages)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,total,const DeepCollectionEquality().hash(_items),page,pages); + +@override +String toString() { + return 'ChildProfileResponseModel(total: $total, items: $items, page: $page, pages: $pages)'; +} + + +} + +/// @nodoc +abstract mixin class _$ChildProfileResponseModelCopyWith<$Res> implements $ChildProfileResponseModelCopyWith<$Res> { + factory _$ChildProfileResponseModelCopyWith(_ChildProfileResponseModel value, $Res Function(_ChildProfileResponseModel) _then) = __$ChildProfileResponseModelCopyWithImpl; +@override @useResult +$Res call({ + int total, List items, int page, int pages +}); + + + + +} +/// @nodoc +class __$ChildProfileResponseModelCopyWithImpl<$Res> + implements _$ChildProfileResponseModelCopyWith<$Res> { + __$ChildProfileResponseModelCopyWithImpl(this._self, this._then); + + final _ChildProfileResponseModel _self; + final $Res Function(_ChildProfileResponseModel) _then; + +/// Create a copy of ChildProfileResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? total = null,Object? items = null,Object? page = null,Object? pages = null,}) { + return _then(_ChildProfileResponseModel( +total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable +as int,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable +as List,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable +as int,pages: null == pages ? _self.pages : pages // ignore: cast_nullable_to_non_nullable +as int, + )); +} + + +} + + +/// @nodoc +mixin _$ChildProfileModel { + + String get id; String get deviceIdentificator; String get parentId; String get firstName; String get lastName; int get bornAt; String get walletId; String get treezorUserId; String get address; int get createdAt; +/// Create a copy of ChildProfileModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ChildProfileModelCopyWith get copyWith => _$ChildProfileModelCopyWithImpl(this as ChildProfileModel, _$identity); + + /// Serializes this ChildProfileModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ChildProfileModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.parentId, parentId) || other.parentId == parentId)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bornAt, bornAt) || other.bornAt == bornAt)&&(identical(other.walletId, walletId) || other.walletId == walletId)&&(identical(other.treezorUserId, treezorUserId) || other.treezorUserId == treezorUserId)&&(identical(other.address, address) || other.address == address)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,parentId,firstName,lastName,bornAt,walletId,treezorUserId,address,createdAt); + +@override +String toString() { + return 'ChildProfileModel(id: $id, deviceIdentificator: $deviceIdentificator, parentId: $parentId, firstName: $firstName, lastName: $lastName, bornAt: $bornAt, walletId: $walletId, treezorUserId: $treezorUserId, address: $address, createdAt: $createdAt)'; +} + + +} + +/// @nodoc +abstract mixin class $ChildProfileModelCopyWith<$Res> { + factory $ChildProfileModelCopyWith(ChildProfileModel value, $Res Function(ChildProfileModel) _then) = _$ChildProfileModelCopyWithImpl; +@useResult +$Res call({ + String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt +}); + + + + +} +/// @nodoc +class _$ChildProfileModelCopyWithImpl<$Res> + implements $ChildProfileModelCopyWith<$Res> { + _$ChildProfileModelCopyWithImpl(this._self, this._then); + + final ChildProfileModel _self; + final $Res Function(ChildProfileModel) _then; + +/// Create a copy of ChildProfileModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceIdentificator = null,Object? parentId = null,Object? firstName = null,Object? lastName = null,Object? bornAt = null,Object? walletId = null,Object? treezorUserId = null,Object? address = null,Object? createdAt = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable +as String,parentId: null == parentId ? _self.parentId : parentId // ignore: cast_nullable_to_non_nullable +as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable +as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable +as String,bornAt: null == bornAt ? _self.bornAt : bornAt // ignore: cast_nullable_to_non_nullable +as int,walletId: null == walletId ? _self.walletId : walletId // ignore: cast_nullable_to_non_nullable +as String,treezorUserId: null == treezorUserId ? _self.treezorUserId : treezorUserId // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ChildProfileModel]. +extension ChildProfileModelPatterns on ChildProfileModel { +/// 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( _ChildProfileModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ChildProfileModel() 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( _ChildProfileModel value) $default,){ +final _that = this; +switch (_that) { +case _ChildProfileModel(): +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( _ChildProfileModel value)? $default,){ +final _that = this; +switch (_that) { +case _ChildProfileModel() 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( String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ChildProfileModel() when $default != null: +return $default(_that.id,_that.deviceIdentificator,_that.parentId,_that.firstName,_that.lastName,_that.bornAt,_that.walletId,_that.treezorUserId,_that.address,_that.createdAt);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( String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt) $default,) {final _that = this; +switch (_that) { +case _ChildProfileModel(): +return $default(_that.id,_that.deviceIdentificator,_that.parentId,_that.firstName,_that.lastName,_that.bornAt,_that.walletId,_that.treezorUserId,_that.address,_that.createdAt);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( String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt)? $default,) {final _that = this; +switch (_that) { +case _ChildProfileModel() when $default != null: +return $default(_that.id,_that.deviceIdentificator,_that.parentId,_that.firstName,_that.lastName,_that.bornAt,_that.walletId,_that.treezorUserId,_that.address,_that.createdAt);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _ChildProfileModel implements ChildProfileModel { + const _ChildProfileModel({required this.id, required this.deviceIdentificator, required this.parentId, required this.firstName, required this.lastName, required this.bornAt, required this.walletId, required this.treezorUserId, required this.address, required this.createdAt}); + factory _ChildProfileModel.fromJson(Map json) => _$ChildProfileModelFromJson(json); + +@override final String id; +@override final String deviceIdentificator; +@override final String parentId; +@override final String firstName; +@override final String lastName; +@override final int bornAt; +@override final String walletId; +@override final String treezorUserId; +@override final String address; +@override final int createdAt; + +/// Create a copy of ChildProfileModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ChildProfileModelCopyWith<_ChildProfileModel> get copyWith => __$ChildProfileModelCopyWithImpl<_ChildProfileModel>(this, _$identity); + +@override +Map toJson() { + return _$ChildProfileModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChildProfileModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.parentId, parentId) || other.parentId == parentId)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bornAt, bornAt) || other.bornAt == bornAt)&&(identical(other.walletId, walletId) || other.walletId == walletId)&&(identical(other.treezorUserId, treezorUserId) || other.treezorUserId == treezorUserId)&&(identical(other.address, address) || other.address == address)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,parentId,firstName,lastName,bornAt,walletId,treezorUserId,address,createdAt); + +@override +String toString() { + return 'ChildProfileModel(id: $id, deviceIdentificator: $deviceIdentificator, parentId: $parentId, firstName: $firstName, lastName: $lastName, bornAt: $bornAt, walletId: $walletId, treezorUserId: $treezorUserId, address: $address, createdAt: $createdAt)'; +} + + +} + +/// @nodoc +abstract mixin class _$ChildProfileModelCopyWith<$Res> implements $ChildProfileModelCopyWith<$Res> { + factory _$ChildProfileModelCopyWith(_ChildProfileModel value, $Res Function(_ChildProfileModel) _then) = __$ChildProfileModelCopyWithImpl; +@override @useResult +$Res call({ + String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt +}); + + + + +} +/// @nodoc +class __$ChildProfileModelCopyWithImpl<$Res> + implements _$ChildProfileModelCopyWith<$Res> { + __$ChildProfileModelCopyWithImpl(this._self, this._then); + + final _ChildProfileModel _self; + final $Res Function(_ChildProfileModel) _then; + +/// Create a copy of ChildProfileModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceIdentificator = null,Object? parentId = null,Object? firstName = null,Object? lastName = null,Object? bornAt = null,Object? walletId = null,Object? treezorUserId = null,Object? address = null,Object? createdAt = null,}) { + return _then(_ChildProfileModel( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable +as String,parentId: null == parentId ? _self.parentId : parentId // ignore: cast_nullable_to_non_nullable +as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable +as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable +as String,bornAt: null == bornAt ? _self.bornAt : bornAt // ignore: cast_nullable_to_non_nullable +as int,walletId: null == walletId ? _self.walletId : walletId // ignore: cast_nullable_to_non_nullable +as String,treezorUserId: null == treezorUserId ? _self.treezorUserId : treezorUserId // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int, + )); +} + + +} + +// dart format on diff --git a/packages/sf_shared/lib/src/data/models/child_profile_response_model.g.dart b/packages/sf_shared/lib/src/data/models/child_profile_response_model.g.dart new file mode 100644 index 00000000..c6b1e986 --- /dev/null +++ b/packages/sf_shared/lib/src/data/models/child_profile_response_model.g.dart @@ -0,0 +1,55 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'child_profile_response_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_ChildProfileResponseModel _$ChildProfileResponseModelFromJson( + Map json, +) => _ChildProfileResponseModel( + total: (json['total'] as num).toInt(), + items: (json['items'] as List) + .map((e) => ChildProfileModel.fromJson(e as Map)) + .toList(), + page: (json['page'] as num).toInt(), + pages: (json['pages'] as num).toInt(), +); + +Map _$ChildProfileResponseModelToJson( + _ChildProfileResponseModel instance, +) => { + 'total': instance.total, + 'items': instance.items, + 'page': instance.page, + 'pages': instance.pages, +}; + +_ChildProfileModel _$ChildProfileModelFromJson(Map json) => + _ChildProfileModel( + id: json['id'] as String, + deviceIdentificator: json['deviceIdentificator'] as String, + parentId: json['parentId'] as String, + firstName: json['firstName'] as String, + lastName: json['lastName'] as String, + bornAt: (json['bornAt'] as num).toInt(), + walletId: json['walletId'] as String, + treezorUserId: json['treezorUserId'] as String, + address: json['address'] as String, + createdAt: (json['createdAt'] as num).toInt(), + ); + +Map _$ChildProfileModelToJson(_ChildProfileModel instance) => + { + 'id': instance.id, + 'deviceIdentificator': instance.deviceIdentificator, + 'parentId': instance.parentId, + 'firstName': instance.firstName, + 'lastName': instance.lastName, + 'bornAt': instance.bornAt, + 'walletId': instance.walletId, + 'treezorUserId': instance.treezorUserId, + 'address': instance.address, + 'createdAt': instance.createdAt, + }; diff --git a/modules/auth/lib/src/core/data/models/payment_profile_response_model.dart b/packages/sf_shared/lib/src/data/models/payment_profile_response_model.dart similarity index 94% rename from modules/auth/lib/src/core/data/models/payment_profile_response_model.dart rename to packages/sf_shared/lib/src/data/models/payment_profile_response_model.dart index ac9d295b..d9e04632 100644 --- a/modules/auth/lib/src/core/data/models/payment_profile_response_model.dart +++ b/packages/sf_shared/lib/src/data/models/payment_profile_response_model.dart @@ -1,4 +1,4 @@ -import 'package:auth/src/features/login/domain/entities/payment_profile_entity.dart'; +import 'package:sf_shared/src/domain/entities/payment_profile_entity.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'payment_profile_response_model.freezed.dart'; @@ -26,7 +26,6 @@ abstract class PaymentProfileItemModel with _$PaymentProfileItemModel { required List taxResidences, required List addresses, required String status, - //talk with Hector to change those names in the backend to be more consistent with the rest of the fields // ignore: non_constant_identifier_names required String KYCStatus, // ignore: non_constant_identifier_names diff --git a/modules/auth/lib/src/core/data/models/payment_profile_response_model.freezed.dart b/packages/sf_shared/lib/src/data/models/payment_profile_response_model.freezed.dart similarity index 99% rename from modules/auth/lib/src/core/data/models/payment_profile_response_model.freezed.dart rename to packages/sf_shared/lib/src/data/models/payment_profile_response_model.freezed.dart index a1f5314d..4d865691 100644 --- a/modules/auth/lib/src/core/data/models/payment_profile_response_model.freezed.dart +++ b/packages/sf_shared/lib/src/data/models/payment_profile_response_model.freezed.dart @@ -296,8 +296,7 @@ $PaymentProfileItemModelCopyWith<$Res> get item { /// @nodoc mixin _$PaymentProfileItemModel { - String get id; String get userId; String get paymentProfileId; String? get jwt; int get bornAt; String get phone; List get taxResidences; List get addresses; String get status;//talk with Hector to change those names in the backend to be more consistent with the rest of the fields -// ignore: non_constant_identifier_names + String get id; String get userId; String get paymentProfileId; String? get jwt; int get bornAt; String get phone; List get taxResidences; List get addresses; String get status;// ignore: non_constant_identifier_names String get KYCStatus;// ignore: non_constant_identifier_names String get KYCLevel; String get placeOfBirth; String get birthCountry; String get nationality; String get documentType; String get document; String? get paymentWalletId; int get createdAt; /// Create a copy of PaymentProfileItemModel @@ -534,7 +533,6 @@ class _PaymentProfileItemModel implements PaymentProfileItemModel { } @override final String status; -//talk with Hector to change those names in the backend to be more consistent with the rest of the fields // ignore: non_constant_identifier_names @override final String KYCStatus; // ignore: non_constant_identifier_names diff --git a/modules/auth/lib/src/core/data/models/payment_profile_response_model.g.dart b/packages/sf_shared/lib/src/data/models/payment_profile_response_model.g.dart similarity index 100% rename from modules/auth/lib/src/core/data/models/payment_profile_response_model.g.dart rename to packages/sf_shared/lib/src/data/models/payment_profile_response_model.g.dart diff --git a/modules/auth/lib/src/core/data/models/user_response_model.dart b/packages/sf_shared/lib/src/data/models/user_response_model.dart similarity index 65% rename from modules/auth/lib/src/core/data/models/user_response_model.dart rename to packages/sf_shared/lib/src/data/models/user_response_model.dart index 52ca848e..da09da10 100644 --- a/modules/auth/lib/src/core/data/models/user_response_model.dart +++ b/packages/sf_shared/lib/src/data/models/user_response_model.dart @@ -1,4 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sf_shared/src/domain/entities/user_entity.dart'; part 'user_response_model.freezed.dart'; part 'user_response_model.g.dart'; @@ -34,3 +35,24 @@ abstract class UserModel with _$UserModel { factory UserModel.fromJson(Map json) => _$UserModelFromJson(json); } + +extension UserModelMapper on UserModel { + UserEntity toEntity() { + return UserEntity( + id: id, + delegationId: delegationId, + email: email, + createdAt: createdAt, + updatedAt: updatedAt, + status: status, + role: role, + lastLogin: lastLogin, + currentLogin: currentLogin, + language: language, + firstName: firstName, + lastName: lastName, + hasApiKey: hasApiKey, + phone: phone, + ); + } +} diff --git a/modules/auth/lib/src/core/data/models/user_response_model.freezed.dart b/packages/sf_shared/lib/src/data/models/user_response_model.freezed.dart similarity index 100% rename from modules/auth/lib/src/core/data/models/user_response_model.freezed.dart rename to packages/sf_shared/lib/src/data/models/user_response_model.freezed.dart diff --git a/modules/auth/lib/src/core/data/models/user_response_model.g.dart b/packages/sf_shared/lib/src/data/models/user_response_model.g.dart similarity index 100% rename from modules/auth/lib/src/core/data/models/user_response_model.g.dart rename to packages/sf_shared/lib/src/data/models/user_response_model.g.dart diff --git a/packages/sf_shared/lib/src/data/repositories/treezor_repository_impl.dart b/packages/sf_shared/lib/src/data/repositories/treezor_repository_impl.dart index 3c7fcb34..e4dd30c9 100644 --- a/packages/sf_shared/lib/src/data/repositories/treezor_repository_impl.dart +++ b/packages/sf_shared/lib/src/data/repositories/treezor_repository_impl.dart @@ -1,4 +1,6 @@ +import 'package:sf_shared/src/data/models/payment_profile_response_model.dart'; import 'package:sf_shared/src/data/models/sca_wallet_model.dart'; +import 'package:sf_shared/src/domain/entities/payment_profile_entity.dart'; import 'package:sf_shared/src/domain/entities/sca_wallet_entity.dart'; import 'package:sf_shared/src/domain/repositories/treezor_repository.dart'; @@ -55,4 +57,12 @@ class TreezorRepositoryImpl implements TreezorRepository { Future sendJWSSesion({required String jws}) { return _remote.sendJWSSesion(jws: jws); } + + @override + Future getPaymentProfile({ + required String userId, + }) async { + final model = await _remote.getPaymentProfile(userId: userId); + return model.toEntity(); + } } diff --git a/packages/sf_shared/lib/src/data/repositories/user_repository_impl.dart b/packages/sf_shared/lib/src/data/repositories/user_repository_impl.dart new file mode 100644 index 00000000..b4bd0c38 --- /dev/null +++ b/packages/sf_shared/lib/src/data/repositories/user_repository_impl.dart @@ -0,0 +1,25 @@ +import 'package:sf_shared/src/data/models/child_profile_response_model.dart'; +import 'package:sf_shared/src/data/models/user_response_model.dart'; +import 'package:sf_shared/src/domain/entities/child_profile_entity.dart'; +import 'package:sf_shared/src/domain/entities/user_entity.dart'; +import 'package:sf_shared/src/domain/repositories/user_repository.dart'; + +import '../datasource/user_remote_datasource.dart'; + +class UserRepositoryImpl implements UserRepository { + UserRepositoryImpl(this._remote); + + final UserRemoteDatasource _remote; + + @override + Future getUserInfo() async { + final model = await _remote.getUserInfo(); + return model.toEntity(); + } + + @override + Future> getChildProfiles() async { + final model = await _remote.getChildProfiles(); + return model.items.map((item) => item.toEntity()).toList(); + } +} diff --git a/packages/sf_shared/lib/src/domain/entities/child_profile_entity.dart b/packages/sf_shared/lib/src/domain/entities/child_profile_entity.dart new file mode 100644 index 00000000..c1febd13 --- /dev/null +++ b/packages/sf_shared/lib/src/domain/entities/child_profile_entity.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'child_profile_entity.freezed.dart'; + +@freezed +abstract class ChildProfileEntity with _$ChildProfileEntity { + const factory ChildProfileEntity({ + required String id, + required String deviceIdentificator, + required String parentId, + required String firstName, + required String lastName, + required int bornAt, + required String walletId, + required String treezorUserId, + required String address, + required int createdAt, + }) = _ChildProfileEntity; +} diff --git a/packages/sf_shared/lib/src/domain/entities/child_profile_entity.freezed.dart b/packages/sf_shared/lib/src/domain/entities/child_profile_entity.freezed.dart new file mode 100644 index 00000000..5f0478df --- /dev/null +++ b/packages/sf_shared/lib/src/domain/entities/child_profile_entity.freezed.dart @@ -0,0 +1,298 @@ +// 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 'child_profile_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ChildProfileEntity { + + String get id; String get deviceIdentificator; String get parentId; String get firstName; String get lastName; int get bornAt; String get walletId; String get treezorUserId; String get address; int get createdAt; +/// Create a copy of ChildProfileEntity +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ChildProfileEntityCopyWith get copyWith => _$ChildProfileEntityCopyWithImpl(this as ChildProfileEntity, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ChildProfileEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.parentId, parentId) || other.parentId == parentId)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bornAt, bornAt) || other.bornAt == bornAt)&&(identical(other.walletId, walletId) || other.walletId == walletId)&&(identical(other.treezorUserId, treezorUserId) || other.treezorUserId == treezorUserId)&&(identical(other.address, address) || other.address == address)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,parentId,firstName,lastName,bornAt,walletId,treezorUserId,address,createdAt); + +@override +String toString() { + return 'ChildProfileEntity(id: $id, deviceIdentificator: $deviceIdentificator, parentId: $parentId, firstName: $firstName, lastName: $lastName, bornAt: $bornAt, walletId: $walletId, treezorUserId: $treezorUserId, address: $address, createdAt: $createdAt)'; +} + + +} + +/// @nodoc +abstract mixin class $ChildProfileEntityCopyWith<$Res> { + factory $ChildProfileEntityCopyWith(ChildProfileEntity value, $Res Function(ChildProfileEntity) _then) = _$ChildProfileEntityCopyWithImpl; +@useResult +$Res call({ + String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt +}); + + + + +} +/// @nodoc +class _$ChildProfileEntityCopyWithImpl<$Res> + implements $ChildProfileEntityCopyWith<$Res> { + _$ChildProfileEntityCopyWithImpl(this._self, this._then); + + final ChildProfileEntity _self; + final $Res Function(ChildProfileEntity) _then; + +/// Create a copy of ChildProfileEntity +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceIdentificator = null,Object? parentId = null,Object? firstName = null,Object? lastName = null,Object? bornAt = null,Object? walletId = null,Object? treezorUserId = null,Object? address = null,Object? createdAt = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable +as String,parentId: null == parentId ? _self.parentId : parentId // ignore: cast_nullable_to_non_nullable +as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable +as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable +as String,bornAt: null == bornAt ? _self.bornAt : bornAt // ignore: cast_nullable_to_non_nullable +as int,walletId: null == walletId ? _self.walletId : walletId // ignore: cast_nullable_to_non_nullable +as String,treezorUserId: null == treezorUserId ? _self.treezorUserId : treezorUserId // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ChildProfileEntity]. +extension ChildProfileEntityPatterns on ChildProfileEntity { +/// 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( _ChildProfileEntity value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ChildProfileEntity() 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( _ChildProfileEntity value) $default,){ +final _that = this; +switch (_that) { +case _ChildProfileEntity(): +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( _ChildProfileEntity value)? $default,){ +final _that = this; +switch (_that) { +case _ChildProfileEntity() 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( String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ChildProfileEntity() when $default != null: +return $default(_that.id,_that.deviceIdentificator,_that.parentId,_that.firstName,_that.lastName,_that.bornAt,_that.walletId,_that.treezorUserId,_that.address,_that.createdAt);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( String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt) $default,) {final _that = this; +switch (_that) { +case _ChildProfileEntity(): +return $default(_that.id,_that.deviceIdentificator,_that.parentId,_that.firstName,_that.lastName,_that.bornAt,_that.walletId,_that.treezorUserId,_that.address,_that.createdAt);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( String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt)? $default,) {final _that = this; +switch (_that) { +case _ChildProfileEntity() when $default != null: +return $default(_that.id,_that.deviceIdentificator,_that.parentId,_that.firstName,_that.lastName,_that.bornAt,_that.walletId,_that.treezorUserId,_that.address,_that.createdAt);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ChildProfileEntity implements ChildProfileEntity { + const _ChildProfileEntity({required this.id, required this.deviceIdentificator, required this.parentId, required this.firstName, required this.lastName, required this.bornAt, required this.walletId, required this.treezorUserId, required this.address, required this.createdAt}); + + +@override final String id; +@override final String deviceIdentificator; +@override final String parentId; +@override final String firstName; +@override final String lastName; +@override final int bornAt; +@override final String walletId; +@override final String treezorUserId; +@override final String address; +@override final int createdAt; + +/// Create a copy of ChildProfileEntity +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ChildProfileEntityCopyWith<_ChildProfileEntity> get copyWith => __$ChildProfileEntityCopyWithImpl<_ChildProfileEntity>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChildProfileEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.parentId, parentId) || other.parentId == parentId)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bornAt, bornAt) || other.bornAt == bornAt)&&(identical(other.walletId, walletId) || other.walletId == walletId)&&(identical(other.treezorUserId, treezorUserId) || other.treezorUserId == treezorUserId)&&(identical(other.address, address) || other.address == address)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,parentId,firstName,lastName,bornAt,walletId,treezorUserId,address,createdAt); + +@override +String toString() { + return 'ChildProfileEntity(id: $id, deviceIdentificator: $deviceIdentificator, parentId: $parentId, firstName: $firstName, lastName: $lastName, bornAt: $bornAt, walletId: $walletId, treezorUserId: $treezorUserId, address: $address, createdAt: $createdAt)'; +} + + +} + +/// @nodoc +abstract mixin class _$ChildProfileEntityCopyWith<$Res> implements $ChildProfileEntityCopyWith<$Res> { + factory _$ChildProfileEntityCopyWith(_ChildProfileEntity value, $Res Function(_ChildProfileEntity) _then) = __$ChildProfileEntityCopyWithImpl; +@override @useResult +$Res call({ + String id, String deviceIdentificator, String parentId, String firstName, String lastName, int bornAt, String walletId, String treezorUserId, String address, int createdAt +}); + + + + +} +/// @nodoc +class __$ChildProfileEntityCopyWithImpl<$Res> + implements _$ChildProfileEntityCopyWith<$Res> { + __$ChildProfileEntityCopyWithImpl(this._self, this._then); + + final _ChildProfileEntity _self; + final $Res Function(_ChildProfileEntity) _then; + +/// Create a copy of ChildProfileEntity +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceIdentificator = null,Object? parentId = null,Object? firstName = null,Object? lastName = null,Object? bornAt = null,Object? walletId = null,Object? treezorUserId = null,Object? address = null,Object? createdAt = null,}) { + return _then(_ChildProfileEntity( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable +as String,parentId: null == parentId ? _self.parentId : parentId // ignore: cast_nullable_to_non_nullable +as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable +as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable +as String,bornAt: null == bornAt ? _self.bornAt : bornAt // ignore: cast_nullable_to_non_nullable +as int,walletId: null == walletId ? _self.walletId : walletId // ignore: cast_nullable_to_non_nullable +as String,treezorUserId: null == treezorUserId ? _self.treezorUserId : treezorUserId // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int, + )); +} + + +} + +// dart format on diff --git a/modules/auth/lib/src/features/login/domain/entities/payment_profile_entity.dart b/packages/sf_shared/lib/src/domain/entities/payment_profile_entity.dart similarity index 100% rename from modules/auth/lib/src/features/login/domain/entities/payment_profile_entity.dart rename to packages/sf_shared/lib/src/domain/entities/payment_profile_entity.dart diff --git a/modules/auth/lib/src/features/login/domain/entities/payment_profile_entity.freezed.dart b/packages/sf_shared/lib/src/domain/entities/payment_profile_entity.freezed.dart similarity index 100% rename from modules/auth/lib/src/features/login/domain/entities/payment_profile_entity.freezed.dart rename to packages/sf_shared/lib/src/domain/entities/payment_profile_entity.freezed.dart diff --git a/modules/auth/lib/src/features/login/domain/entities/user_entity.dart b/packages/sf_shared/lib/src/domain/entities/user_entity.dart similarity index 100% rename from modules/auth/lib/src/features/login/domain/entities/user_entity.dart rename to packages/sf_shared/lib/src/domain/entities/user_entity.dart diff --git a/modules/auth/lib/src/features/login/domain/entities/user_entity.freezed.dart b/packages/sf_shared/lib/src/domain/entities/user_entity.freezed.dart similarity index 100% rename from modules/auth/lib/src/features/login/domain/entities/user_entity.freezed.dart rename to packages/sf_shared/lib/src/domain/entities/user_entity.freezed.dart diff --git a/packages/sf_shared/lib/src/domain/repositories/treezor_repository.dart b/packages/sf_shared/lib/src/domain/repositories/treezor_repository.dart index 5504c219..98e0e3f0 100644 --- a/packages/sf_shared/lib/src/domain/repositories/treezor_repository.dart +++ b/packages/sf_shared/lib/src/domain/repositories/treezor_repository.dart @@ -1,3 +1,4 @@ +import '../entities/payment_profile_entity.dart'; import '../entities/sca_wallet_entity.dart'; abstract class TreezorRepository { @@ -6,4 +7,6 @@ abstract class TreezorRepository { Future resetScaWallets(); Future sendJWSSesion({required String jws}); + + Future getPaymentProfile({required String userId}); } diff --git a/packages/sf_shared/lib/src/domain/repositories/user_repository.dart b/packages/sf_shared/lib/src/domain/repositories/user_repository.dart new file mode 100644 index 00000000..f4ea07c2 --- /dev/null +++ b/packages/sf_shared/lib/src/domain/repositories/user_repository.dart @@ -0,0 +1,7 @@ +import '../entities/child_profile_entity.dart'; +import '../entities/user_entity.dart'; + +abstract class UserRepository { + Future getUserInfo(); + Future> getChildProfiles(); +} diff --git a/packages/sf_shared/lib/src/domain/use_cases/get_payment_profile_use_case.dart b/packages/sf_shared/lib/src/domain/use_cases/get_payment_profile_use_case.dart new file mode 100644 index 00000000..634da872 --- /dev/null +++ b/packages/sf_shared/lib/src/domain/use_cases/get_payment_profile_use_case.dart @@ -0,0 +1,5 @@ +import '../entities/payment_profile_entity.dart'; + +abstract class GetPaymentProfileUseCase { + Future getPaymentProfile({required String userId}); +} diff --git a/packages/sf_shared/lib/src/domain/use_cases/get_payment_profile_use_case_impl.dart b/packages/sf_shared/lib/src/domain/use_cases/get_payment_profile_use_case_impl.dart new file mode 100644 index 00000000..beba0d37 --- /dev/null +++ b/packages/sf_shared/lib/src/domain/use_cases/get_payment_profile_use_case_impl.dart @@ -0,0 +1,16 @@ +import '../entities/payment_profile_entity.dart'; +import '../repositories/treezor_repository.dart'; +import 'get_payment_profile_use_case.dart'; + +class GetPaymentProfileUseCaseImpl implements GetPaymentProfileUseCase { + const GetPaymentProfileUseCaseImpl(this._repository); + + final TreezorRepository _repository; + + @override + Future getPaymentProfile({ + required String userId, + }) { + return _repository.getPaymentProfile(userId: userId); + } +} diff --git a/modules/auth/lib/src/features/login/domain/get_me_user_use_case.dart b/packages/sf_shared/lib/src/domain/use_cases/get_user_info_use_case.dart similarity index 50% rename from modules/auth/lib/src/features/login/domain/get_me_user_use_case.dart rename to packages/sf_shared/lib/src/domain/use_cases/get_user_info_use_case.dart index 85820f6e..7acd7cc5 100644 --- a/modules/auth/lib/src/features/login/domain/get_me_user_use_case.dart +++ b/packages/sf_shared/lib/src/domain/use_cases/get_user_info_use_case.dart @@ -1,4 +1,4 @@ -import 'package:auth/src/features/login/domain/entities/user_entity.dart'; +import '../entities/user_entity.dart'; abstract class GetUserInfoUseCase { Future getUserInfo(); diff --git a/packages/sf_shared/lib/src/domain/use_cases/get_user_info_use_case_impl.dart b/packages/sf_shared/lib/src/domain/use_cases/get_user_info_use_case_impl.dart new file mode 100644 index 00000000..558bc78a --- /dev/null +++ b/packages/sf_shared/lib/src/domain/use_cases/get_user_info_use_case_impl.dart @@ -0,0 +1,14 @@ +import '../entities/user_entity.dart'; +import '../repositories/user_repository.dart'; +import 'get_user_info_use_case.dart'; + +class GetUserInfoUseCaseImpl implements GetUserInfoUseCase { + const GetUserInfoUseCaseImpl(this._repository); + + final UserRepository _repository; + + @override + Future getUserInfo() { + return _repository.getUserInfo(); + } +} diff --git a/packages/sf_shared/lib/src/providers/get_payment_profile_use_case_provider.dart b/packages/sf_shared/lib/src/providers/get_payment_profile_use_case_provider.dart new file mode 100644 index 00000000..ca1fd37a --- /dev/null +++ b/packages/sf_shared/lib/src/providers/get_payment_profile_use_case_provider.dart @@ -0,0 +1,11 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:sf_shared/src/domain/use_cases/get_payment_profile_use_case.dart'; +import 'package:sf_shared/src/domain/use_cases/get_payment_profile_use_case_impl.dart'; +import 'package:sf_shared/src/providers/treezor_repository_provider.dart'; + +final getPaymentProfileUseCaseProvider = + Provider((ref) { + final repository = ref.watch(treezorRepositoryProvider); + return GetPaymentProfileUseCaseImpl(repository); +}); diff --git a/packages/sf_shared/lib/src/providers/get_user_info_use_case_provider.dart b/packages/sf_shared/lib/src/providers/get_user_info_use_case_provider.dart new file mode 100644 index 00000000..1dee9ebb --- /dev/null +++ b/packages/sf_shared/lib/src/providers/get_user_info_use_case_provider.dart @@ -0,0 +1,11 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:sf_shared/src/domain/use_cases/get_user_info_use_case.dart'; +import 'package:sf_shared/src/domain/use_cases/get_user_info_use_case_impl.dart'; +import 'package:sf_shared/src/providers/user_repository_provider.dart'; + +final getUserInfoUseCaseProvider = + Provider((ref) { + final repository = ref.watch(userRepositoryProvider); + return GetUserInfoUseCaseImpl(repository); +}); diff --git a/packages/sf_shared/lib/src/providers/user_info_provider.dart b/packages/sf_shared/lib/src/providers/user_info_provider.dart new file mode 100644 index 00000000..cfe06e48 --- /dev/null +++ b/packages/sf_shared/lib/src/providers/user_info_provider.dart @@ -0,0 +1,8 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:sf_shared/sf_shared.dart'; + +final userInfoProvider = + FutureProvider.autoDispose((ref) async { + final getUserInfoUseCase = ref.read(getUserInfoUseCaseProvider); + return getUserInfoUseCase.getUserInfo(); +}); diff --git a/packages/sf_shared/lib/src/providers/user_repository_provider.dart b/packages/sf_shared/lib/src/providers/user_repository_provider.dart new file mode 100644 index 00000000..8f184b7c --- /dev/null +++ b/packages/sf_shared/lib/src/providers/user_repository_provider.dart @@ -0,0 +1,12 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:get_it/get_it.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; +import 'package:sf_shared/src/data/datasource/user_remote_datasource_impl.dart'; +import 'package:sf_shared/src/data/repositories/user_repository_impl.dart'; +import 'package:sf_shared/src/domain/repositories/user_repository.dart'; + +final userRepositoryProvider = Provider((ref) { + final questiaRepository = GetIt.I(); + final remote = UserRemoteDatasourceImpl(questiaRepository); + return UserRepositoryImpl(remote); +}); diff --git a/packages/sf_shared/lib/src/widgets/line_graph.dart b/packages/sf_shared/lib/src/widgets/line_graph.dart index e4d6ce8f..a9595cb5 100644 --- a/packages/sf_shared/lib/src/widgets/line_graph.dart +++ b/packages/sf_shared/lib/src/widgets/line_graph.dart @@ -86,7 +86,7 @@ class LineGraphState extends ConsumerState { return SideTitleWidget( space: 4, meta: meta, - child: Expanded(child: Center(child: Text(text, style: TextStyle(fontSize: 12)))), + child: Center(child: Text(text, style: TextStyle(fontSize: 12))), ); }, ),