profile settings screen to show user information, move getPaymentProfile,getUserInfo,getChildProfiles request to sf shared, some refactors

This commit is contained in:
2026-02-12 14:32:57 +01:00
parent 417f0021ad
commit d96985bf54
65 changed files with 1597 additions and 415 deletions

View File

@@ -80,7 +80,7 @@ class PlatformAppState extends ConsumerState<PlatformApp>
routerConfig: appRouter,
debugShowCheckedModeBanner: false,
localizationsDelegates: [
// CountryLocalizations.getDelegate(enableLocalization: false),
// CountryLocalizations.delegate,
SFLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,

View File

@@ -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,
),
],
),
],
),

View File

@@ -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<UserModel> getUserInfo();
Future<void> requestPhoneCode({required String phone});
Future<void> verifyPhoneCode({required String phone, required String code});
@@ -44,8 +40,6 @@ abstract class AuthRemoteDatasource {
Future<void> createWallet();
Future<PaymentProfileResponseModel> getPaymentProfile({required String userId});
Future<ChildProfileResponseModel> createChildProfile({
required String id,
required String parentId,

View File

@@ -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<UserModel> getUserInfo() async {
try {
final response = await _repository.get<Map<String, dynamic>>('/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<void> requestPhoneCode({required String phone}) async {
@@ -283,29 +265,6 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
}
}
@override
Future<PaymentProfileResponseModel> getPaymentProfile({
required String userId,
}) async {
try {
final response = await _repository.get<Map<String, dynamic>>(
'/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<ChildProfileResponseModel> createChildProfile({
required String id,

View File

@@ -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,
);
}
}

View File

@@ -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<UserEntity> getUserInfo() async {
final model = await _remote.getUserInfo();
return model.toEntity();
}
@override
Future<void> createWallet() {
return _remote.createWallet();
}
@override
Future<PaymentProfileEntity> getPaymentProfile({
required String userId,
}) async {
final model = await _remote.getPaymentProfile(userId: userId);
return model.toEntity();
}
// @override
// Future<String> totpLogin({required String token, required String code}) {
// return _remote.totpLogin(token: token, code: code);

View File

@@ -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<UserEntity> getUserInfo();
Future<void> createWallet();
Future<PaymentProfileEntity> getPaymentProfile({required String userId});
// Future<String> totpLogin({required String token, required String code});
Future<SignUpResponseEntity> signUp({required SignUpRequestEntity request});

View File

@@ -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<DeviceSetupViewState> {
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<DeviceSetupViewState> {
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: '');

View File

@@ -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<UserEntity> getUserInfo() {
return _repository.getUserInfo();
}
}

View File

@@ -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<GetUserInfoUseCase>((
ref,
) {
final authRepository = ref.read(authRepositoryProvider);
return GetUserInfoUseCaseImpl(authRepository);
});

View File

@@ -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<LoginViewModel, LoginViewState>(

View File

@@ -32,6 +32,8 @@ class SCATreezorViewModel extends Notifier<SCATreezorViewState> {
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<SCATreezorViewState> {
_connectionService = GetIt.I<TreezorWalletConnectionService>();
_signatureService = GetIt.I<TreezorWalletSignatureService>();
_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<SCATreezorViewState> {
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<SCATreezorViewState> {
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

View File

@@ -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<Kid> 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<NavigationContract>();
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(

View File

@@ -1,2 +1,3 @@
export 'src/presentation/profile_screen.dart';
export 'src/profile_builder.dart';
export 'src/profile_settings_builder.dart';

View File

@@ -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),
),
),
),
);
},

View File

@@ -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<Widget>.generate(kids.length, (int index){
children: List<Widget>.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),

View File

@@ -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}';
}
}

View File

@@ -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<void> buildPage(BuildContext context, GoRouterState state) {
return MaterialPage(child: ProfileScreen());
final navigationContract = GetIt.I<NavigationContract>();
return MaterialPage(
key: state.pageKey,
child: ProfileScreen(navigationContract: navigationContract),
);
}
}

View File

@@ -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<void> buildPage(BuildContext context, GoRouterState state) {
final navigationContract = GetIt.I<NavigationContract>();
return MaterialPage(
key: state.pageKey,
child: ProfileSettingsScreen(navigationContract: navigationContract),
);
}
}

View File

@@ -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<ProfileSettingsData>((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,
);
});

View File

@@ -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

View File

@@ -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:

View File

@@ -1,3 +0,0 @@
abstract class SplashRemoteDatasource {
Future<List<dynamic>> getChildProfiles();
}

View File

@@ -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<List<dynamic>> getChildProfiles() async {
final response =
await _repository.get<Map<String, dynamic>>('/child-profiles');
final data = response.data;
if (data == null) return [];
final items = data['items'] ?? data['data'] ?? [];
return items is List ? items : [];
}
}

View File

@@ -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<InitialRoute> 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');

View File

@@ -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<void> buildPage(BuildContext context, GoRouterState state) {
final navigationContract = GetIt.I<NavigationContract>();
final datasource = SplashRemoteDatasourceImpl(GetIt.I<QuestiaRepository>());
final checkSessionUseCase = CheckSessionUseCaseImpl(datasource);
final remote = UserRemoteDatasourceImpl(GetIt.I<QuestiaRepository>());
final userRepository = UserRepositoryImpl(remote);
final checkSessionUseCase = CheckSessionUseCaseImpl(userRepository);
return NoTransitionPage(
child: SplashScreen(

View File

@@ -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

View File

@@ -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

View File

@@ -7,6 +7,6 @@
<versions>
<version>2.6.4</version>
</versions>
<lastUpdated>20260210000000</lastUpdated>
<lastUpdated>20260212000000</lastUpdated>
</versioning>
</metadata>

View File

@@ -1 +1 @@
d77d08495d6aeaec19114b634957c84c
299dd618be3c19b3aced93d75bb14a01

View File

@@ -1 +1 @@
bdcbc45dfb9b2a6ccb485f2e1114aeef96a11ce7
9967947368e66f19dfcef5b3d016f0fdfd89f20e

View File

@@ -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';
}

View File

@@ -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';

View File

@@ -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<ScaWalletsResponseModel> scaWallets();
Future<bool> sendJWSSesion({required String jws});
Future<PaymentProfileResponseModel> getPaymentProfile({
required String userId,
});
}

View File

@@ -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<PaymentProfileResponseModel> getPaymentProfile({
required String userId,
}) async {
try {
final response = await _repository.get<Map<String, dynamic>>(
'/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}) {

View File

@@ -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<UserModel> getUserInfo();
Future<ChildProfileResponseModel> getChildProfiles();
}

View File

@@ -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<UserModel> getUserInfo() async {
try {
final response = await _repository.get<Map<String, dynamic>>('/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<ChildProfileResponseModel> getChildProfiles() async {
final response =
await _repository.get<Map<String, dynamic>>('/child-profiles');
final data = response.data;
if (data == null) {
throw Exception('Empty response from /child-profiles');
}
return ChildProfileResponseModel.fromJson(data);
}
}

View File

@@ -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<ChildProfileModel> items,
required int page,
required int pages,
}) = _ChildProfileResponseModel;
factory ChildProfileResponseModel.fromJson(Map<String, dynamic> 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<String, dynamic> 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,
);
}
}

View File

@@ -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>(T value) => value;
/// @nodoc
mixin _$ChildProfileResponseModel {
int get total; List<ChildProfileModel> 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<ChildProfileResponseModel> get copyWith => _$ChildProfileResponseModelCopyWithImpl<ChildProfileResponseModel>(this as ChildProfileResponseModel, _$identity);
/// Serializes this ChildProfileResponseModel to a JSON map.
Map<String, dynamic> 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<ChildProfileModel> 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<ChildProfileModel>,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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(TResult Function( int total, List<ChildProfileModel> 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 extends Object?>(TResult Function( int total, List<ChildProfileModel> 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 extends Object?>(TResult? Function( int total, List<ChildProfileModel> 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<ChildProfileModel> items, required this.page, required this.pages}): _items = items;
factory _ChildProfileResponseModel.fromJson(Map<String, dynamic> json) => _$ChildProfileResponseModelFromJson(json);
@override final int total;
final List<ChildProfileModel> _items;
@override List<ChildProfileModel> 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<String, dynamic> 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<ChildProfileModel> 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<ChildProfileModel>,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<ChildProfileModel> get copyWith => _$ChildProfileModelCopyWithImpl<ChildProfileModel>(this as ChildProfileModel, _$identity);
/// Serializes this ChildProfileModel to a JSON map.
Map<String, dynamic> 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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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<String, dynamic> 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<String, dynamic> 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

View File

@@ -0,0 +1,55 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'child_profile_response_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_ChildProfileResponseModel _$ChildProfileResponseModelFromJson(
Map<String, dynamic> json,
) => _ChildProfileResponseModel(
total: (json['total'] as num).toInt(),
items: (json['items'] as List<dynamic>)
.map((e) => ChildProfileModel.fromJson(e as Map<String, dynamic>))
.toList(),
page: (json['page'] as num).toInt(),
pages: (json['pages'] as num).toInt(),
);
Map<String, dynamic> _$ChildProfileResponseModelToJson(
_ChildProfileResponseModel instance,
) => <String, dynamic>{
'total': instance.total,
'items': instance.items,
'page': instance.page,
'pages': instance.pages,
};
_ChildProfileModel _$ChildProfileModelFromJson(Map<String, dynamic> 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<String, dynamic> _$ChildProfileModelToJson(_ChildProfileModel instance) =>
<String, dynamic>{
'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,
};

View File

@@ -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<PaymentProfileAddressModel> taxResidences,
required List<PaymentProfileAddressModel> 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

View File

@@ -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<PaymentProfileAddressModel> get taxResidences; List<PaymentProfileAddressModel> 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<PaymentProfileAddressModel> get taxResidences; List<PaymentProfileAddressModel> 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

View File

@@ -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<String, dynamic> 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,
);
}
}

View File

@@ -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<bool> sendJWSSesion({required String jws}) {
return _remote.sendJWSSesion(jws: jws);
}
@override
Future<PaymentProfileEntity> getPaymentProfile({
required String userId,
}) async {
final model = await _remote.getPaymentProfile(userId: userId);
return model.toEntity();
}
}

View File

@@ -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<UserEntity> getUserInfo() async {
final model = await _remote.getUserInfo();
return model.toEntity();
}
@override
Future<List<ChildProfileEntity>> getChildProfiles() async {
final model = await _remote.getChildProfiles();
return model.items.map((item) => item.toEntity()).toList();
}
}

View File

@@ -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;
}

View File

@@ -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>(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<ChildProfileEntity> get copyWith => _$ChildProfileEntityCopyWithImpl<ChildProfileEntity>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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

View File

@@ -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<void> resetScaWallets();
Future<bool> sendJWSSesion({required String jws});
Future<PaymentProfileEntity> getPaymentProfile({required String userId});
}

View File

@@ -0,0 +1,7 @@
import '../entities/child_profile_entity.dart';
import '../entities/user_entity.dart';
abstract class UserRepository {
Future<UserEntity> getUserInfo();
Future<List<ChildProfileEntity>> getChildProfiles();
}

View File

@@ -0,0 +1,5 @@
import '../entities/payment_profile_entity.dart';
abstract class GetPaymentProfileUseCase {
Future<PaymentProfileEntity> getPaymentProfile({required String userId});
}

View File

@@ -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<PaymentProfileEntity> getPaymentProfile({
required String userId,
}) {
return _repository.getPaymentProfile(userId: userId);
}
}

View File

@@ -1,4 +1,4 @@
import 'package:auth/src/features/login/domain/entities/user_entity.dart';
import '../entities/user_entity.dart';
abstract class GetUserInfoUseCase {
Future<UserEntity> getUserInfo();

View File

@@ -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<UserEntity> getUserInfo() {
return _repository.getUserInfo();
}
}

View File

@@ -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<GetPaymentProfileUseCase>((ref) {
final repository = ref.watch(treezorRepositoryProvider);
return GetPaymentProfileUseCaseImpl(repository);
});

View File

@@ -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<GetUserInfoUseCase>((ref) {
final repository = ref.watch(userRepositoryProvider);
return GetUserInfoUseCaseImpl(repository);
});

View File

@@ -0,0 +1,8 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_shared/sf_shared.dart';
final userInfoProvider =
FutureProvider.autoDispose<UserEntity>((ref) async {
final getUserInfoUseCase = ref.read(getUserInfoUseCaseProvider);
return getUserInfoUseCase.getUserInfo();
});

View File

@@ -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<UserRepository>((ref) {
final questiaRepository = GetIt.I<QuestiaRepository>();
final remote = UserRemoteDatasourceImpl(questiaRepository);
return UserRepositoryImpl(remote);
});

View File

@@ -86,7 +86,7 @@ class LineGraphState extends ConsumerState<LineGraph> {
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))),
);
},
),