diff --git a/apps/mobile/packages/domain/lib/krow_domain.dart b/apps/mobile/packages/domain/lib/krow_domain.dart index abe46636..710b8989 100644 --- a/apps/mobile/packages/domain/lib/krow_domain.dart +++ b/apps/mobile/packages/domain/lib/krow_domain.dart @@ -84,3 +84,4 @@ export 'src/entities/availability/day_availability.dart'; export 'src/adapters/profile/emergency_contact_adapter.dart'; export 'src/adapters/profile/experience_adapter.dart'; export 'src/entities/profile/experience_skill.dart'; +export 'src/adapters/profile/bank_account_adapter.dart'; diff --git a/apps/mobile/packages/domain/lib/src/adapters/profile/bank_account_adapter.dart b/apps/mobile/packages/domain/lib/src/adapters/profile/bank_account_adapter.dart new file mode 100644 index 00000000..6b285b8a --- /dev/null +++ b/apps/mobile/packages/domain/lib/src/adapters/profile/bank_account_adapter.dart @@ -0,0 +1,53 @@ +import '../../entities/profile/bank_account.dart'; + +/// Adapter for [BankAccount] to map data layer values to domain entity. +class BankAccountAdapter { + /// Maps primitive values to [BankAccount]. + static BankAccount fromPrimitives({ + required String id, + required String userId, + required String bankName, + required String? type, + String? accountNumber, + String? last4, + String? sortCode, + bool? isPrimary, + }) { + return BankAccount( + id: id, + userId: userId, + bankName: bankName, + accountNumber: accountNumber ?? '', + accountName: '', // Not provided by backend + last4: last4, + sortCode: sortCode, + type: _stringToType(type), + isPrimary: isPrimary ?? false, + ); + } + + static BankAccountType _stringToType(String? value) { + if (value == null) return BankAccountType.checking; + try { + // Assuming backend enum names match or are uppercase + return BankAccountType.values.firstWhere( + (e) => e.name.toLowerCase() == value.toLowerCase(), + orElse: () => BankAccountType.other, + ); + } catch (_) { + return BankAccountType.other; + } + } + + /// Converts domain type to string for backend. + static String typeToString(BankAccountType type) { + switch (type) { + case BankAccountType.checking: + return 'CHECKING'; + case BankAccountType.savings: + return 'SAVINGS'; + default: + return 'CHECKING'; + } + } +} diff --git a/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/data/repositories/bank_account_repository_impl.dart b/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/data/repositories/bank_account_repository_impl.dart index 6014f2d7..f98e7c15 100644 --- a/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/data/repositories/bank_account_repository_impl.dart +++ b/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/data/repositories/bank_account_repository_impl.dart @@ -2,58 +2,47 @@ import 'package:firebase_auth/firebase_auth.dart' as auth; import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:krow_data_connect/krow_data_connect.dart'; import 'package:krow_domain/krow_domain.dart'; - import '../../domain/repositories/bank_account_repository.dart'; -/// Implementation of [BankAccountRepository]. +/// Implementation of [BankAccountRepository] that integrates with Data Connect. class BankAccountRepositoryImpl implements BankAccountRepository { + /// Creates a [BankAccountRepositoryImpl]. const BankAccountRepositoryImpl({ required this.dataConnect, required this.firebaseAuth, }); + /// The Data Connect instance. final ExampleConnector dataConnect; + /// The Firebase Auth instance. final auth.FirebaseAuth firebaseAuth; @override Future> getAccounts() async { - final auth.User? user = firebaseAuth.currentUser; - if (user == null) throw Exception('User not authenticated'); - final String? staffId = StaffSessionStore.instance.session?.staff?.id; - if (staffId == null || staffId.isEmpty) { - print('BankAccount getAccounts: missing staffId userId=${user.uid} session=${StaffSessionStore.instance.session}'); - throw Exception('Staff profile is missing.'); - } - + final String staffId = _getStaffId(); + final QueryResult result = await dataConnect .getAccountsByOwnerId(ownerId: staffId) .execute(); return result.data.accounts.map((GetAccountsByOwnerIdAccounts account) { - return BankAccount( + return BankAccountAdapter.fromPrimitives( id: account.id, userId: account.ownerId, bankName: account.bank, - accountNumber: account.accountNumber ?? '', + accountNumber: account.accountNumber, last4: account.last4, - accountName: '', // Not returned by API sortCode: account.routeNumber, - type: _mapAccountType(account.type), - isPrimary: account.isPrimary ?? false, + type: account.type is Known ? (account.type as Known).value.name : null, + isPrimary: account.isPrimary, ); }).toList(); } @override Future addAccount(BankAccount account) async { - final auth.User? user = firebaseAuth.currentUser; - if (user == null) throw Exception('User not authenticated'); - final String? staffId = StaffSessionStore.instance.session?.staff?.id; - if (staffId == null || staffId.isEmpty) { - print('BankAccount addAccount: missing staffId userId=${user.uid} session=${StaffSessionStore.instance.session}'); - throw Exception('Staff profile is missing.'); - } + final String staffId = _getStaffId(); final QueryResult existingAccounts = await dataConnect @@ -64,44 +53,41 @@ class BankAccountRepositoryImpl implements BankAccountRepository { await dataConnect.createAccount( bank: account.bankName, - type: _mapDomainType(account.type), + type: AccountType.values.byName(BankAccountAdapter.typeToString(account.type)), last4: _safeLast4(account.last4, account.accountNumber), ownerId: staffId, - ).isPrimary(isPrimary).accountNumber(account.accountNumber).routeNumber(account.sortCode).execute(); + ) + .isPrimary(isPrimary) + .accountNumber(account.accountNumber) + .routeNumber(account.sortCode) + .execute(); } - BankAccountType _mapAccountType(EnumValue type) { - if (type is Known) { - switch (type.value) { - case AccountType.CHECKING: - return BankAccountType.checking; - case AccountType.SAVINGS: - return BankAccountType.savings; - } + /// Helper to get the logged-in staff ID. + String _getStaffId() { + final auth.User? user = firebaseAuth.currentUser; + if (user == null) { + throw Exception('User not authenticated'); } - return BankAccountType.other; - } - - AccountType _mapDomainType(BankAccountType type) { - switch (type) { - case BankAccountType.checking: - return AccountType.CHECKING; - case BankAccountType.savings: - return AccountType.SAVINGS; - default: - return AccountType.CHECKING; // Default fallback + + final String? staffId = StaffSessionStore.instance.session?.staff?.id; + if (staffId == null || staffId.isEmpty) { + throw Exception('Staff profile is missing or session not initialized.'); } + return staffId; } + /// Ensures we have a last4 value, either from input or derived from account number. String _safeLast4(String? last4, String accountNumber) { if (last4 != null && last4.isNotEmpty) { return last4; } if (accountNumber.isEmpty) { - return ''; + return '0000'; } - return accountNumber.length > 4 - ? accountNumber.substring(accountNumber.length - 4) - : accountNumber; + if (accountNumber.length < 4) { + return accountNumber.padLeft(4, '0'); + } + return accountNumber.substring(accountNumber.length - 4); } } diff --git a/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/presentation/blocs/bank_account_cubit.dart b/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/presentation/blocs/bank_account_cubit.dart index 16b1dff8..5baac87a 100644 --- a/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/presentation/blocs/bank_account_cubit.dart +++ b/apps/mobile/packages/features/staff/profile_sections/finances/staff_bank_account/lib/src/presentation/blocs/bank_account_cubit.dart @@ -1,5 +1,4 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:krow_core/core.dart'; import 'package:krow_domain/krow_domain.dart'; import '../../domain/arguments/add_bank_account_params.dart'; import '../../domain/usecases/add_bank_account_usecase.dart'; @@ -20,7 +19,7 @@ class BankAccountCubit extends Cubit { Future loadAccounts() async { emit(state.copyWith(status: BankAccountStatus.loading)); try { - final accounts = await _getBankAccountsUseCase(); + final List accounts = await _getBankAccountsUseCase(); emit(state.copyWith( status: BankAccountStatus.loaded, accounts: accounts, @@ -45,7 +44,7 @@ class BankAccountCubit extends Cubit { emit(state.copyWith(status: BankAccountStatus.loading)); // Create domain entity - final newAccount = BankAccount( + final BankAccount newAccount = BankAccount( id: '', // Generated by server usually userId: '', // Handled by Repo/Auth bankName: 'New Bank', // Mock diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/experience/lib/staff_profile_experience.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/experience/lib/staff_profile_experience.dart index 51474bb3..ab4c83e9 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/experience/lib/staff_profile_experience.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/experience/lib/staff_profile_experience.dart @@ -40,7 +40,7 @@ class StaffProfileExperienceModule extends Module { ); // BLoC - i.addLazySingleton( + i.add( () => ExperienceBloc( getIndustries: i.get(), getSkills: i.get(),