feat: Implement staff profile completion feature with new repository and use case

This commit is contained in:
Achintha Isuru
2026-02-19 12:15:46 -05:00
parent f0c33339ef
commit faa0403314
8 changed files with 101 additions and 88 deletions

View File

@@ -17,3 +17,8 @@ export 'src/services/mixins/session_handler_mixin.dart';
export 'src/session/staff_session_store.dart';
export 'src/services/mixins/data_error_handler.dart';
// Export Staff Connector repositories and use cases
export 'src/connectors/staff/domain/repositories/staff_connector_repository.dart';
export 'src/connectors/staff/domain/usecases/get_profile_completion_usecase.dart';
export 'src/connectors/staff/data/repositories/staff_connector_repository_impl.dart';

View File

@@ -0,0 +1,61 @@
import 'package:firebase_data_connect/firebase_data_connect.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import '../../domain/repositories/staff_connector_repository.dart';
/// Implementation of [StaffConnectorRepository].
///
/// Fetches staff-related data from the Data Connect backend using
/// the staff connector queries.
class StaffConnectorRepositoryImpl implements StaffConnectorRepository {
/// Creates a new [StaffConnectorRepositoryImpl].
///
/// Requires a [DataConnectService] instance for backend communication.
StaffConnectorRepositoryImpl({
DataConnectService? service,
}) : _service = service ?? DataConnectService.instance;
final DataConnectService _service;
@override
Future<bool> getProfileCompletion() async {
return _service.run(() async {
final String staffId = await _service.getStaffId();
final QueryResult<GetStaffProfileCompletionData,
GetStaffProfileCompletionVariables> response =
await _service.connector
.getStaffProfileCompletion(id: staffId)
.execute();
final GetStaffProfileCompletionStaff? staff = response.data.staff;
final List<GetStaffProfileCompletionEmergencyContacts>
emergencyContacts = response.data.emergencyContacts;
final List<GetStaffProfileCompletionTaxForms> taxForms =
response.data.taxForms;
return _isProfileComplete(staff, emergencyContacts, taxForms);
});
}
/// Checks if staff has experience data (skills or industries).
bool _hasExperience(GetStaffProfileCompletionStaff? staff) {
if (staff == null) return false;
final dynamic skills = staff.skills;
final dynamic industries = staff.industries;
return (skills is List && skills.isNotEmpty) ||
(industries is List && industries.isNotEmpty);
}
/// Determines if the profile is complete based on all sections.
bool _isProfileComplete(
GetStaffProfileCompletionStaff? staff,
List<GetStaffProfileCompletionEmergencyContacts> emergencyContacts,
List<GetStaffProfileCompletionTaxForms> taxForms,
) {
return staff != null &&
emergencyContacts.isNotEmpty &&
taxForms.isNotEmpty &&
_hasExperience(staff);
}
}

View File

@@ -0,0 +1,13 @@
/// Repository interface for staff connector queries.
///
/// This interface defines the contract for accessing staff-related data
/// from the backend via Data Connect.
abstract interface class StaffConnectorRepository {
/// Fetches whether the profile is complete for the current staff member.
///
/// Returns true if all required profile sections have been completed,
/// false otherwise.
///
/// Throws an exception if the query fails.
Future<bool> getProfileCompletion();
}

View File

@@ -1,19 +1,19 @@
import '../repositories/profile_completion_repository.dart';
import '../repositories/staff_connector_repository.dart';
/// Use case for retrieving profile completion status.
/// Use case for retrieving staff profile completion status.
///
/// This use case encapsulates the business logic for determining whether
/// a staff member's profile is complete. It delegates to the repository
/// for data access.
class GetProfileCompletionUsecase {
/// Creates a [GetProfileCompletionUsecase].
class GetProfileCompletionUseCase {
/// Creates a [GetProfileCompletionUseCase].
///
/// Requires a [ProfileCompletionRepositoryInterface] for data access.
GetProfileCompletionUsecase({
required ProfileCompletionRepositoryInterface repository,
/// Requires a [StaffConnectorRepository] for data access.
GetProfileCompletionUseCase({
required StaffConnectorRepository repository,
}) : _repository = repository;
final ProfileCompletionRepositoryInterface _repository;
final StaffConnectorRepository _repository;
/// Executes the use case to get profile completion status.
///

View File

@@ -1,55 +0,0 @@
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:staff_main/src/domain/repositories/profile_completion_repository.dart';
/// Implementation of [ProfileCompletionRepositoryInterface].
///
/// Fetches profile completion status from the Data Connect backend.
class ProfileCompletionRepositoryImpl implements ProfileCompletionRepositoryInterface {
/// Creates a new [ProfileCompletionRepositoryImpl].
///
/// Requires a [DataConnectService] instance for backend communication.
ProfileCompletionRepositoryImpl({
DataConnectService? service,
}) : _service = service ?? DataConnectService.instance;
final DataConnectService _service;
@override
Future<bool> getProfileCompletion() async {
return _service.run(() async {
final String staffId = await _service.getStaffId();
final response = await _service.connector
.getStaffProfileCompletion(id: staffId)
.execute();
final staff = response.data.staff;
final emergencyContacts = response.data.emergencyContacts;
final taxForms = response.data.taxForms;
return _isProfileComplete(staff, emergencyContacts, taxForms);
});
}
/// Checks if staff has experience data (skills or industries).
bool _hasExperience(dynamic staff) {
if (staff == null) return false;
final skills = staff.skills;
final industries = staff.industries;
return (skills is List && skills.isNotEmpty) ||
(industries is List && industries.isNotEmpty);
}
/// Determines if the profile is complete based on all sections.
bool _isProfileComplete(
dynamic staff,
List<dynamic> emergencyContacts,
List<dynamic> taxForms,
) {
return staff != null &&
emergencyContacts.isNotEmpty &&
taxForms.isNotEmpty &&
_hasExperience(staff);
}
}

View File

@@ -1,13 +0,0 @@
/// Repository interface for profile completion status queries.
///
/// This interface defines the contract for accessing profile completion data.
/// Implementations should fetch this data from the backend via Data Connect.
abstract interface class ProfileCompletionRepositoryInterface {
/// Fetches whether the profile is complete for the current staff member.
///
/// Returns true if all required profile sections have been completed,
/// false otherwise.
///
/// Throws an exception if the query fails.
Future<bool> getProfileCompletion();
}

View File

@@ -1,13 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_core/core.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:staff_main/src/domain/usecases/get_profile_completion_usecase.dart';
import 'package:staff_main/src/presentation/blocs/staff_main_state.dart';
class StaffMainCubit extends Cubit<StaffMainState> implements Disposable {
StaffMainCubit({
required GetProfileCompletionUsecase getProfileCompletionUsecase,
required GetProfileCompletionUseCase getProfileCompletionUsecase,
}) : _getProfileCompletionUsecase = getProfileCompletionUsecase,
super(const StaffMainState()) {
Modular.to.addListener(_onRouteChanged);
@@ -15,7 +15,7 @@ class StaffMainCubit extends Cubit<StaffMainState> implements Disposable {
_loadProfileCompletion();
}
final GetProfileCompletionUsecase _getProfileCompletionUsecase;
final GetProfileCompletionUseCase _getProfileCompletionUsecase;
void _onRouteChanged() {
if (isClosed) return;

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/core.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:staff_attire/staff_attire.dart';
import 'package:staff_availability/staff_availability.dart';
import 'package:staff_bank_account/staff_bank_account.dart';
@@ -10,9 +11,6 @@ import 'package:staff_documents/staff_documents.dart';
import 'package:staff_emergency_contact/staff_emergency_contact.dart';
import 'package:staff_faqs/staff_faqs.dart';
import 'package:staff_home/staff_home.dart';
import 'package:staff_main/src/data/repositories/profile_completion_repository_impl.dart';
import 'package:staff_main/src/domain/repositories/profile_completion_repository.dart';
import 'package:staff_main/src/domain/usecases/get_profile_completion_usecase.dart';
import 'package:staff_main/src/presentation/blocs/staff_main_cubit.dart';
import 'package:staff_main/src/presentation/pages/staff_main_page.dart';
import 'package:staff_payments/staff_payements.dart';
@@ -27,17 +25,21 @@ import 'package:staff_time_card/staff_time_card.dart';
class StaffMainModule extends Module {
@override
void binds(Injector i) {
i.addSingleton<ProfileCompletionRepositoryInterface>(
ProfileCompletionRepositoryImpl.new,
// Register the StaffConnectorRepository from data_connect
i.addSingleton<StaffConnectorRepository>(
StaffConnectorRepositoryImpl.new,
);
// Register the use case from data_connect
i.addSingleton(
() => GetProfileCompletionUsecase(
repository: i.get<ProfileCompletionRepositoryInterface>(),
() => GetProfileCompletionUseCase(
repository: i.get<StaffConnectorRepository>(),
),
);
i.addSingleton(
i.add(
() => StaffMainCubit(
getProfileCompletionUsecase: i.get<GetProfileCompletionUsecase>(),
getProfileCompletionUsecase: i.get<GetProfileCompletionUseCase>(),
),
);
}