feat: Migrate staff profile features from Data Connect to V2 REST API

- Removed data_connect package from mobile pubspec.yaml.
- Added documentation for V2 profile migration status and QA findings.
- Implemented new session management with ClientSessionStore and StaffSessionStore.
- Created V2SessionService for handling user sessions via the V2 API.
- Developed use cases for cancelling late worker assignments and submitting worker reviews.
- Added arguments and use cases for payment chart retrieval and profile completion checks.
- Implemented repository interfaces and their implementations for staff main and profile features.
- Ensured proper error handling and validation in use cases.
This commit is contained in:
Achintha Isuru
2026-03-16 22:45:06 -04:00
parent 4834266986
commit b31a615092
478 changed files with 10512 additions and 19854 deletions

View File

@@ -0,0 +1,42 @@
import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/staff_main_repository_interface.dart';
/// V2 API implementation of [StaffMainRepositoryInterface].
///
/// Calls `GET /staff/profile-completion` and parses the response into a
/// [ProfileCompletion] entity to determine completion status.
class StaffMainRepositoryImpl implements StaffMainRepositoryInterface {
/// Creates a [StaffMainRepositoryImpl].
StaffMainRepositoryImpl({required BaseApiService apiService})
: _apiService = apiService;
/// The API service used for network requests.
final BaseApiService _apiService;
/// Fetches profile completion from the V2 API.
///
/// Returns `true` when all required profile sections are complete.
/// Defaults to `true` on error so that navigation is not blocked.
@override
Future<bool> getProfileCompletion() async {
try {
final ApiResponse response = await _apiService.get(
V2ApiEndpoints.staffProfileCompletion,
);
if (response.data is Map<String, dynamic>) {
final ProfileCompletion completion = ProfileCompletion.fromJson(
response.data as Map<String, dynamic>,
);
return completion.completed;
}
return true;
} catch (_) {
// Allow full access on error to avoid blocking navigation.
return true;
}
}
}

View File

@@ -0,0 +1,7 @@
/// Repository interface for staff main shell data access.
///
/// Provides profile-completion status used to gate bottom-bar tabs.
abstract interface class StaffMainRepositoryInterface {
/// Returns `true` when all required profile sections are complete.
Future<bool> getProfileCompletion();
}

View File

@@ -0,0 +1,20 @@
import 'package:krow_core/core.dart';
import 'package:staff_main/src/domain/repositories/staff_main_repository_interface.dart';
/// Use case for retrieving staff profile completion status.
///
/// Delegates to [StaffMainRepositoryInterface] for backend access and
/// returns `true` when all required profile sections are complete.
class GetProfileCompletionUseCase extends NoInputUseCase<bool> {
/// Creates a [GetProfileCompletionUseCase].
GetProfileCompletionUseCase({
required StaffMainRepositoryInterface repository,
}) : _repository = repository;
/// The repository used for data access.
final StaffMainRepositoryInterface _repository;
/// Fetches whether the staff profile is complete.
@override
Future<bool> call() => _repository.getProfileCompletion();
}

View File

@@ -1,26 +1,36 @@
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:krow_core/core.dart';
import 'package:staff_main/src/domain/usecases/get_profile_completion_usecase.dart';
import 'package:staff_main/src/presentation/blocs/staff_main_state.dart';
/// Cubit that manages the staff main shell state.
///
/// Tracks the active bottom-bar tab index, profile completion status, and
/// bottom bar visibility based on the current route.
class StaffMainCubit extends Cubit<StaffMainState> implements Disposable {
/// Creates a [StaffMainCubit].
StaffMainCubit({
required GetProfileCompletionUseCase getProfileCompletionUsecase,
}) : _getProfileCompletionUsecase = getProfileCompletionUsecase,
super(const StaffMainState()) {
}) : _getProfileCompletionUsecase = getProfileCompletionUsecase,
super(const StaffMainState()) {
Modular.to.addListener(_onRouteChanged);
_onRouteChanged();
}
/// The use case for checking profile completion.
final GetProfileCompletionUseCase _getProfileCompletionUsecase;
/// Guard flag to prevent concurrent profile-completion fetches.
bool _isLoadingCompletion = false;
/// Routes that should hide the bottom navigation bar.
static const List<String> _hideBottomPaths = <String>[
StaffPaths.benefits,
];
/// Listener invoked whenever the Modular route changes.
void _onRouteChanged() {
if (isClosed) return;
@@ -46,18 +56,19 @@ class StaffMainCubit extends Cubit<StaffMainState> implements Disposable {
final bool showBottomBar = !_hideBottomPaths.any(path.contains);
if (newIndex != state.currentIndex || showBottomBar != state.showBottomBar) {
if (newIndex != state.currentIndex ||
showBottomBar != state.showBottomBar) {
emit(state.copyWith(currentIndex: newIndex, showBottomBar: showBottomBar));
}
}
/// Loads the profile completion status.
/// Loads the profile completion status from the V2 API.
Future<void> refreshProfileCompletion() async {
if (_isLoadingCompletion || isClosed) return;
_isLoadingCompletion = true;
try {
final isComplete = await _getProfileCompletionUsecase();
final bool isComplete = await _getProfileCompletionUsecase();
if (!isClosed) {
emit(state.copyWith(isProfileComplete: isComplete));
}
@@ -72,6 +83,7 @@ class StaffMainCubit extends Cubit<StaffMainState> implements Disposable {
}
}
/// Navigates to the tab at [index].
void navigateToTab(int index) {
if (index == state.currentIndex) return;

View File

@@ -1,7 +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:krow_domain/krow_domain.dart' show BaseApiService;
import 'package:staff_attire/staff_attire.dart';
import 'package:staff_availability/staff_availability.dart';
import 'package:staff_bank_account/staff_bank_account.dart';
@@ -11,6 +11,9 @@ 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/staff_main_repository_impl.dart';
import 'package:staff_main/src/domain/repositories/staff_main_repository_interface.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';
@@ -22,22 +25,32 @@ import 'package:staff_shifts/staff_shifts.dart';
import 'package:staff_tax_forms/staff_tax_forms.dart';
import 'package:staff_time_card/staff_time_card.dart';
/// The main module for the staff app shell.
///
/// Registers navigation routes for all staff features and provides
/// profile-completion gating via [StaffMainCubit].
class StaffMainModule extends Module {
@override
List<Module> get imports => <Module>[CoreModule()];
@override
void binds(Injector i) {
// Register the StaffConnectorRepository from data_connect
i.addLazySingleton<StaffConnectorRepository>(
StaffConnectorRepositoryImpl.new,
);
// Register the use case from data_connect
i.addLazySingleton(
() => GetProfileCompletionUseCase(
repository: i.get<StaffConnectorRepository>(),
// Repository backed by V2 REST API
i.addLazySingleton<StaffMainRepositoryInterface>(
() => StaffMainRepositoryImpl(
apiService: i.get<BaseApiService>(),
),
);
i.add(
// Use case for profile completion check
i.addLazySingleton<GetProfileCompletionUseCase>(
() => GetProfileCompletionUseCase(
repository: i.get<StaffMainRepositoryInterface>(),
),
);
// Main shell cubit
i.add<StaffMainCubit>(
() => StaffMainCubit(
getProfileCompletionUsecase: i.get<GetProfileCompletionUseCase>(),
),

View File

@@ -22,8 +22,8 @@ dependencies:
path: ../../../core_localization
krow_core:
path: ../../../core
krow_data_connect:
path: ../../../data_connect
krow_domain:
path: ../../../domain
# Features
staff_home: