From 098ae1d476cbacafbedef267d701389293a7574b Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Mon, 26 Jan 2026 20:35:34 -0500 Subject: [PATCH] Refactor PersonalInfoRepository to use Firebase Auth for user profile retrieval and remove mock implementation --- .../personal_info_repository_impl.dart | 46 ++++++++++----- .../personal_info_repository_mock.dart | 59 ------------------- .../personal_info_repository_interface.dart | 4 +- .../usecases/get_personal_info_usecase.dart | 17 +----- .../update_personal_info_usecase.dart | 17 +----- .../blocs/personal_info_bloc.dart | 12 ++-- .../lib/src/staff_profile_info_module.dart | 16 ++--- 7 files changed, 52 insertions(+), 119 deletions(-) delete mode 100644 apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_mock.dart diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_impl.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_impl.dart index bac8463e..5e00ed64 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_impl.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_impl.dart @@ -1,3 +1,4 @@ +import 'package:firebase_auth/firebase_auth.dart'; 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'; @@ -14,27 +15,36 @@ import '../../domain/repositories/personal_info_repository_interface.dart'; /// - Containing no business logic class PersonalInfoRepositoryImpl implements PersonalInfoRepositoryInterface { final ExampleConnector _dataConnect; + final FirebaseAuth _firebaseAuth; /// Creates a [PersonalInfoRepositoryImpl]. /// - /// Requires the Firebase Data Connect connector instance. + /// Requires the Firebase Data Connect connector instance and Firebase Auth. PersonalInfoRepositoryImpl({ required ExampleConnector dataConnect, - }) : _dataConnect = dataConnect; + required FirebaseAuth firebaseAuth, + }) : _dataConnect = dataConnect, + _firebaseAuth = firebaseAuth; @override - Future getStaffProfile(String staffId) async { - // Query staff data from Firebase Data Connect - final QueryResult result = - await _dataConnect.getStaffById(id: staffId).execute(); - - final staff = result.data.staff; - if (staff == null) { - throw Exception('Staff profile not found for ID: $staffId'); + Future getStaffProfile() async { + final user = _firebaseAuth.currentUser; + if (user == null) { + throw Exception('User not authenticated'); } + // Query staff data from Firebase Data Connect + final QueryResult result = + await _dataConnect.getStaffByUserId(userId: user.uid).execute(); + + if (result.data.staffs.isEmpty) { + throw Exception('Staff profile not found for User ID: ${user.uid}'); + } + + final rawStaff = result.data.staffs.first; + // Map from data_connect DTO to domain entity - return _mapToStaffEntity(staff); + return _mapToStaffEntity(rawStaff); } @override @@ -54,7 +64,7 @@ class PersonalInfoRepositoryImpl implements PersonalInfoRepositoryInterface { } // Fetch the updated staff profile to return complete entity - return getStaffProfile(staff.id); + return getStaffProfile(); } @override @@ -69,16 +79,22 @@ class PersonalInfoRepositoryImpl implements PersonalInfoRepositoryInterface { /// Maps a data_connect Staff DTO to a domain Staff entity. /// /// This mapping isolates the domain from data layer implementation details. - Staff _mapToStaffEntity(GetStaffByIdStaff dto) { + Staff _mapToStaffEntity(GetStaffByUserIdStaffs dto) { return Staff( id: dto.id, authProviderId: dto.userId, name: dto.fullName, email: dto.email ?? '', phone: dto.phone, - status: StaffStatus.active, // TODO: Map from actual status field when available - address: dto.addres, avatar: dto.photoUrl, + status: StaffStatus.active, + address: dto.addres, + totalShifts: dto.totalShifts, + averageRating: dto.averageRating, + onTimeRate: dto.onTimeRate, + noShowCount: dto.noShowCount, + cancellationCount: dto.cancellationCount, + reliabilityScore: dto.reliabilityScore, ); } } diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_mock.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_mock.dart deleted file mode 100644 index b7b26e44..00000000 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/data/repositories/personal_info_repository_mock.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:krow_domain/krow_domain.dart'; - -import '../../domain/repositories/personal_info_repository_interface.dart'; - -/// Mock implementation of [PersonalInfoRepositoryInterface]. -/// -/// This mock repository returns hardcoded data for development -/// and will be replaced with [PersonalInfoRepositoryImpl] when -/// Firebase Data Connect is fully configured. -/// -/// Following Clean Architecture, this mock: -/// - Implements the domain repository interface -/// - Returns domain entities (Staff) -/// - Simulates async operations with delays -/// - Provides realistic test data -class PersonalInfoRepositoryMock implements PersonalInfoRepositoryInterface { - // Simulated in-memory storage - Staff? _cachedStaff; - - @override - Future getStaffProfile(String staffId) async { - // Simulate network delay - await Future.delayed(const Duration(milliseconds: 500)); - - // Return cached staff or create mock data - return _cachedStaff ?? - const Staff( - id: 'mock-staff-1', - authProviderId: 'mock-auth-1', - name: 'Krower', - email: 'worker@krow.com', - phone: '', - status: StaffStatus.active, - address: 'Montreal, Quebec', - avatar: null, - ); - } - - @override - Future updateStaffProfile(Staff staff) async { - // Simulate network delay - await Future.delayed(const Duration(milliseconds: 800)); - - // Store in cache - _cachedStaff = staff; - - // Return the updated staff - return staff; - } - - @override - Future uploadProfilePhoto(String filePath) async { - // Simulate upload delay - await Future.delayed(const Duration(seconds: 2)); - - // Return a mock URL - return 'https://example.com/photos/${DateTime.now().millisecondsSinceEpoch}.jpg'; - } -} diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/repositories/personal_info_repository_interface.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/repositories/personal_info_repository_interface.dart index bb327203..44ee5747 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/repositories/personal_info_repository_interface.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/repositories/personal_info_repository_interface.dart @@ -8,10 +8,10 @@ import 'package:krow_domain/krow_domain.dart'; /// Implementations must delegate all data operations through /// the data_connect layer, following Clean Architecture principles. abstract interface class PersonalInfoRepositoryInterface { - /// Retrieves the staff profile for the specified staff ID. + /// Retrieves the staff profile for the current authenticated user. /// /// Returns the complete [Staff] entity with all profile information. - Future getStaffProfile(String staffId); + Future getStaffProfile(); /// Updates the staff profile information. /// diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/get_personal_info_usecase.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/get_personal_info_usecase.dart index 51c44264..265e6f8b 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/get_personal_info_usecase.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/get_personal_info_usecase.dart @@ -2,23 +2,12 @@ import 'package:krow_core/core.dart'; import 'package:krow_domain/krow_domain.dart'; import '../repositories/personal_info_repository_interface.dart'; -/// Arguments for getting staff profile information. -class GetPersonalInfoArguments extends UseCaseArgument { - /// The staff member's ID. - final String staffId; - - const GetPersonalInfoArguments({required this.staffId}); - - @override - List get props => [staffId]; -} - /// Use case for retrieving staff profile information. /// /// This use case fetches the complete staff profile from the repository, /// which delegates to the data_connect layer for data access. class GetPersonalInfoUseCase - implements UseCase { + implements NoInputUseCase { final PersonalInfoRepositoryInterface _repository; /// Creates a [GetPersonalInfoUseCase]. @@ -27,7 +16,7 @@ class GetPersonalInfoUseCase GetPersonalInfoUseCase(this._repository); @override - Future call(GetPersonalInfoArguments arguments) { - return _repository.getStaffProfile(arguments.staffId); + Future call() { + return _repository.getStaffProfile(); } } diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/update_personal_info_usecase.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/update_personal_info_usecase.dart index ea399231..ad30452e 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/update_personal_info_usecase.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/domain/usecases/update_personal_info_usecase.dart @@ -2,23 +2,12 @@ import 'package:krow_core/core.dart'; import 'package:krow_domain/krow_domain.dart'; import '../repositories/personal_info_repository_interface.dart'; -/// Arguments for updating staff profile information. -class UpdatePersonalInfoArguments extends UseCaseArgument { - /// The staff entity with updated information. - final Staff staff; - - const UpdatePersonalInfoArguments({required this.staff}); - - @override - List get props => [staff]; -} - /// Use case for updating staff profile information. /// /// This use case updates the staff profile information /// through the repository, which delegates to the data_connect layer. class UpdatePersonalInfoUseCase - implements UseCase { + implements UseCase { final PersonalInfoRepositoryInterface _repository; /// Creates an [UpdatePersonalInfoUseCase]. @@ -27,7 +16,7 @@ class UpdatePersonalInfoUseCase UpdatePersonalInfoUseCase(this._repository); @override - Future call(UpdatePersonalInfoArguments arguments) { - return _repository.updateStaffProfile(arguments.staff); + Future call(Staff arguments) { + return _repository.updateStaffProfile(arguments); } } diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart index 36cffabe..c666dee5 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart @@ -1,5 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; +import 'package:krow_core/core.dart'; import 'package:krow_domain/krow_domain.dart'; import '../../domain/usecases/get_personal_info_usecase.dart'; @@ -16,18 +17,15 @@ class PersonalInfoBloc extends Bloc implements Disposable { final GetPersonalInfoUseCase _getPersonalInfoUseCase; final UpdatePersonalInfoUseCase _updatePersonalInfoUseCase; - final String _staffId; /// Creates a [PersonalInfoBloc]. /// - /// Requires the staff ID to load and update the correct profile. + /// Requires the use cases to load and update the profile. PersonalInfoBloc({ required GetPersonalInfoUseCase getPersonalInfoUseCase, required UpdatePersonalInfoUseCase updatePersonalInfoUseCase, - required String staffId, }) : _getPersonalInfoUseCase = getPersonalInfoUseCase, _updatePersonalInfoUseCase = updatePersonalInfoUseCase, - _staffId = staffId, super(const PersonalInfoState()) { on(_onLoadRequested); on(_onFieldUpdated); @@ -42,9 +40,7 @@ class PersonalInfoBloc extends Bloc ) async { emit(state.copyWith(status: PersonalInfoStatus.loading)); try { - final Staff staff = await _getPersonalInfoUseCase( - GetPersonalInfoArguments(staffId: _staffId), - ); + final Staff staff = await _getPersonalInfoUseCase(); emit(state.copyWith( status: PersonalInfoStatus.loaded, staff: staff, @@ -115,7 +111,7 @@ class PersonalInfoBloc extends Bloc emit(state.copyWith(status: PersonalInfoStatus.saving)); try { final Staff updatedStaff = await _updatePersonalInfoUseCase( - UpdatePersonalInfoArguments(staff: state.staff!), + state.staff!, ); emit(state.copyWith( status: PersonalInfoStatus.saved, diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/staff_profile_info_module.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/staff_profile_info_module.dart index 5679ae1f..984d010a 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/staff_profile_info_module.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/staff_profile_info_module.dart @@ -1,7 +1,9 @@ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; +import 'package:krow_data_connect/krow_data_connect.dart'; -import 'data/repositories/personal_info_repository_mock.dart'; +import 'data/repositories/personal_info_repository_impl.dart'; import 'domain/repositories/personal_info_repository_interface.dart'; import 'domain/usecases/get_personal_info_usecase.dart'; import 'domain/usecases/update_personal_info_usecase.dart'; @@ -14,17 +16,19 @@ import 'presentation/pages/personal_info_page.dart'; /// personal information functionality following Clean Architecture. /// /// The module: -/// - Registers repository implementations (mock for now, will use real impl later) +/// - Registers repository implementations /// - Registers use cases that contain business logic /// - Registers BLoC for state management /// - Defines routes for navigation class StaffProfileInfoModule extends Module { @override void binds(Injector i) { - // Repository - using mock for now - // TODO: Replace with PersonalInfoRepositoryImpl when Firebase Data Connect is configured + // Repository i.addLazySingleton( - PersonalInfoRepositoryMock.new, + () => PersonalInfoRepositoryImpl( + dataConnect: ExampleConnector.instance, + firebaseAuth: FirebaseAuth.instance, + ), ); // Use Cases - delegate business logic to repository @@ -36,12 +40,10 @@ class StaffProfileInfoModule extends Module { ); // BLoC - manages presentation state - // TODO: Get actual staffId from authentication state i.addLazySingleton( () => PersonalInfoBloc( getPersonalInfoUseCase: i.get(), updatePersonalInfoUseCase: i.get(), - staffId: 'mock-staff-1', // TODO: Get from auth ), ); }