feat: Refactor repositories to utilize DataConnectService and remove FirebaseAuth dependency

This commit is contained in:
Achintha Isuru
2026-02-16 16:54:20 -05:00
parent ef58ca83be
commit 17423c5d66
8 changed files with 69 additions and 116 deletions

View File

@@ -1,6 +1,5 @@
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/core.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'data/repositories_impl/attire_repository_impl.dart';
import 'domain/repositories/attire_repository.dart';
@@ -14,10 +13,8 @@ class StaffAttireModule extends Module {
@override
void binds(Injector i) {
// Repository
i.addLazySingleton<AttireRepository>(
() => AttireRepositoryImpl(ExampleConnector.instance),
);
i.addLazySingleton<AttireRepository>(AttireRepositoryImpl.new);
// Use Cases
i.addLazySingleton(GetAttireOptionsUseCase.new);
i.addLazySingleton(SaveAttireUseCase.new);

View File

@@ -6,24 +6,30 @@ import '../../domain/repositories/attire_repository.dart';
/// Implementation of [AttireRepository].
///
/// Delegates data access to [ExampleConnector] from `data_connect`.
/// Delegates data access to [DataConnectService].
class AttireRepositoryImpl implements AttireRepository {
/// The Data Connect connector instance.
final ExampleConnector _connector;
/// The Data Connect service.
final DataConnectService _service;
/// Creates an [AttireRepositoryImpl].
AttireRepositoryImpl(this._connector);
AttireRepositoryImpl({DataConnectService? service})
: _service = service ?? DataConnectService.instance;
@override
Future<List<AttireItem>> getAttireOptions() async {
final QueryResult<ListAttireOptionsData, void> result = await _connector.listAttireOptions().execute();
return result.data.attireOptions.map((ListAttireOptionsAttireOptions e) => AttireItem(
id: e.itemId,
label: e.label,
iconName: e.icon,
imageUrl: e.imageUrl,
isMandatory: e.isMandatory ?? false,
)).toList();
return _service.run(() async {
final QueryResult<ListAttireOptionsData, void> result =
await _service.connector.listAttireOptions().execute();
return result.data.attireOptions
.map((ListAttireOptionsAttireOptions e) => AttireItem(
id: e.itemId,
label: e.label,
iconName: e.icon,
imageUrl: e.imageUrl,
isMandatory: e.isMandatory ?? false,
))
.toList();
});
}
@override

View File

@@ -1,4 +1,3 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/emergency_contact_repository_interface.dart';
@@ -7,38 +6,19 @@ import '../../domain/repositories/emergency_contact_repository_interface.dart';
///
/// This repository delegates data operations to Firebase Data Connect.
class EmergencyContactRepositoryImpl
with dc.DataErrorHandler
implements EmergencyContactRepositoryInterface {
final dc.ExampleConnector _dataConnect;
final FirebaseAuth _firebaseAuth;
final dc.DataConnectService _service;
/// Creates an [EmergencyContactRepositoryImpl].
EmergencyContactRepositoryImpl({
required dc.ExampleConnector dataConnect,
required FirebaseAuth firebaseAuth,
}) : _dataConnect = dataConnect,
_firebaseAuth = firebaseAuth;
Future<String> _getStaffId() async {
final user = _firebaseAuth.currentUser;
if (user == null) {
throw const NotAuthenticatedException(
technicalMessage: 'User not authenticated');
}
final result =
await _dataConnect.getStaffByUserId(userId: user.uid).execute();
if (result.data.staffs.isEmpty) {
throw const ServerException(technicalMessage: 'Staff profile not found');
}
return result.data.staffs.first.id;
}
dc.DataConnectService? service,
}) : _service = service ?? dc.DataConnectService.instance;
@override
Future<List<EmergencyContact>> getContacts() async {
return executeProtected(() async {
final staffId = await _getStaffId();
final result = await _dataConnect
return _service.run(() async {
final staffId = await _service.getStaffId();
final result = await _service.connector
.getEmergencyContactsByStaffId(staffId: staffId)
.execute();
@@ -55,11 +35,11 @@ class EmergencyContactRepositoryImpl
@override
Future<void> saveContacts(List<EmergencyContact> contacts) async {
return executeProtected(() async {
final staffId = await _getStaffId();
return _service.run(() async {
final staffId = await _service.getStaffId();
// 1. Get existing to delete
final existingResult = await _dataConnect
final existingResult = await _service.connector
.getEmergencyContactsByStaffId(staffId: staffId)
.execute();
final existingIds =
@@ -67,7 +47,7 @@ class EmergencyContactRepositoryImpl
// 2. Delete all existing
await Future.wait(existingIds.map(
(id) => _dataConnect.deleteEmergencyContact(id: id).execute()));
(id) => _service.connector.deleteEmergencyContact(id: id).execute()));
// 3. Create new
await Future.wait(contacts.map((contact) {
@@ -87,7 +67,7 @@ class EmergencyContactRepositoryImpl
break;
}
return _dataConnect
return _service.connector
.createEmergencyContact(
name: contact.name,
phone: contact.phone,

View File

@@ -1,6 +1,5 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'data/repositories/emergency_contact_repository_impl.dart';
import 'domain/repositories/emergency_contact_repository_interface.dart';
import 'domain/usecases/get_emergency_contacts_usecase.dart';
@@ -13,10 +12,7 @@ class StaffEmergencyContactModule extends Module {
void binds(Injector i) {
// Repository
i.addLazySingleton<EmergencyContactRepositoryInterface>(
() => EmergencyContactRepositoryImpl(
dataConnect: ExampleConnector.instance,
firebaseAuth: FirebaseAuth.instance,
),
EmergencyContactRepositoryImpl.new,
);
// UseCases

View File

@@ -1,42 +1,31 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import '../../domain/repositories/experience_repository_interface.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/experience_repository_interface.dart';
/// Implementation of [ExperienceRepositoryInterface] that delegates to Data Connect.
class ExperienceRepositoryImpl
with dc.DataErrorHandler
implements ExperienceRepositoryInterface {
final dc.ExampleConnector _dataConnect;
// ignore: unused_field
final FirebaseAuth _firebaseAuth;
class ExperienceRepositoryImpl implements ExperienceRepositoryInterface {
final dc.DataConnectService _service;
/// Creates a [ExperienceRepositoryImpl] using Data Connect and Auth.
/// Creates a [ExperienceRepositoryImpl] using Data Connect Service.
ExperienceRepositoryImpl({
required dc.ExampleConnector dataConnect,
required FirebaseAuth firebaseAuth,
}) : _dataConnect = dataConnect,
_firebaseAuth = firebaseAuth;
dc.DataConnectService? service,
}) : _service = service ?? dc.DataConnectService.instance;
Future<dc.GetStaffByUserIdStaffs> _getStaff() async {
final user = _firebaseAuth.currentUser;
if (user == null) {
throw const NotAuthenticatedException(
technicalMessage: 'User not authenticated');
}
Future<dc.GetStaffByIdStaff> _getStaff() async {
final staffId = await _service.getStaffId();
final result =
await _dataConnect.getStaffByUserId(userId: user.uid).execute();
if (result.data.staffs.isEmpty) {
await _service.connector.getStaffById(id: staffId).execute();
if (result.data.staff == null) {
throw const ServerException(technicalMessage: 'Staff profile not found');
}
return result.data.staffs.first;
return result.data.staff!;
}
@override
Future<List<String>> getIndustries() async {
return executeProtected(() async {
return _service.run(() async {
final staff = await _getStaff();
return staff.industries ?? [];
});
@@ -44,7 +33,7 @@ class ExperienceRepositoryImpl
@override
Future<List<String>> getSkills() async {
return executeProtected(() async {
return _service.run(() async {
final staff = await _getStaff();
return staff.skills ?? [];
});
@@ -55,9 +44,9 @@ class ExperienceRepositoryImpl
List<String> industries,
List<String> skills,
) async {
return executeProtected(() async {
return _service.run(() async {
final staff = await _getStaff();
await _dataConnect
await _service.connector
.updateStaff(id: staff.id)
.industries(industries)
.skills(skills)

View File

@@ -1,6 +1,5 @@
library staff_profile_experience;
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
@@ -22,10 +21,7 @@ class StaffProfileExperienceModule extends Module {
void binds(Injector i) {
// Repository
i.addLazySingleton<ExperienceRepositoryInterface>(
() => ExperienceRepositoryImpl(
dataConnect: ExampleConnector.instance,
firebaseAuth: FirebaseAuth.instance,
),
ExperienceRepositoryImpl.new,
);
// UseCases

View File

@@ -1,4 +1,3 @@
import 'package:firebase_auth/firebase_auth.dart' as firebase_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';
@@ -14,32 +13,24 @@ import '../../domain/repositories/personal_info_repository_interface.dart';
/// - Mapping between data_connect DTOs and domain entities
/// - Containing no business logic
class PersonalInfoRepositoryImpl
with DataErrorHandler
implements PersonalInfoRepositoryInterface {
/// Creates a [PersonalInfoRepositoryImpl].
///
/// Requires the Firebase Data Connect connector instance and Firebase Auth.
/// Requires the Firebase Data Connect service.
PersonalInfoRepositoryImpl({
required ExampleConnector dataConnect,
required firebase_auth.FirebaseAuth firebaseAuth,
}) : _dataConnect = dataConnect,
_firebaseAuth = firebaseAuth;
final ExampleConnector _dataConnect;
final firebase_auth.FirebaseAuth _firebaseAuth;
DataConnectService? service,
}) : _service = service ?? DataConnectService.instance;
final DataConnectService _service;
@override
Future<Staff> getStaffProfile() async {
return executeProtected(() async {
final firebase_auth.User? user = _firebaseAuth.currentUser;
if (user == null) {
throw NotAuthenticatedException(
technicalMessage: 'User not authenticated');
}
return _service.run(() async {
final String uid = _service.auth.currentUser!.uid;
// Query staff data from Firebase Data Connect
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables> result =
await _dataConnect.getStaffByUserId(userId: user.uid).execute();
await _service.connector.getStaffByUserId(userId: uid).execute();
if (result.data.staffs.isEmpty) {
throw const ServerException(technicalMessage: 'Staff profile not found');
@@ -53,10 +44,12 @@ class PersonalInfoRepositoryImpl
}
@override
Future<Staff> updateStaffProfile({required String staffId, required Map<String, dynamic> data}) async {
return executeProtected(() async {
Future<Staff> updateStaffProfile(
{required String staffId, required Map<String, dynamic> data}) async {
return _service.run(() async {
// Start building the update mutation
UpdateStaffVariablesBuilder updateBuilder = _dataConnect.updateStaff(id: staffId);
UpdateStaffVariablesBuilder updateBuilder =
_service.connector.updateStaff(id: staffId);
// Apply updates from map if present
if (data.containsKey('name')) {
@@ -72,8 +65,9 @@ class PersonalInfoRepositoryImpl
updateBuilder = updateBuilder.photoUrl(data['avatar'] as String?);
}
if (data.containsKey('preferredLocations')) {
// After schema update and SDK regeneration, preferredLocations accepts List<String>
updateBuilder = updateBuilder.preferredLocations(data['preferredLocations'] as List<String>);
// After schema update and SDK regeneration, preferredLocations accepts List<String>
updateBuilder = updateBuilder.preferredLocations(
data['preferredLocations'] as List<String>);
}
// Execute the update
@@ -81,7 +75,8 @@ class PersonalInfoRepositoryImpl
await updateBuilder.execute();
if (result.data.staff_update == null) {
throw const ServerException(technicalMessage: 'Failed to update staff profile');
throw const ServerException(
technicalMessage: 'Failed to update staff profile');
}
// Fetch the updated staff profile to return complete entity

View File

@@ -1,7 +1,5 @@
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_impl.dart';
import 'domain/repositories/personal_info_repository_interface.dart';
@@ -25,11 +23,7 @@ class StaffProfileInfoModule extends Module {
void binds(Injector i) {
// Repository
i.addLazySingleton<PersonalInfoRepositoryInterface>(
() => PersonalInfoRepositoryImpl(
dataConnect: ExampleConnector.instance,
firebaseAuth: FirebaseAuth.instance,
),
);
PersonalInfoRepositoryImpl.new);
// Use Cases - delegate business logic to repository
i.addLazySingleton<GetPersonalInfoUseCase>(