Add staff reliability stats & shift location
Introduce staff reliability statistics and location fields across domain, data, and UI. Changes include:
- New API endpoint StaffEndpoints.profileStats ('/staff/profile/stats').
- New domain entity StaffReliabilityStats with JSON (de)serialization and export.
- Profile repository: getReliabilityStats implementation and interface addition.
- New GetReliabilityStatsUseCase and DI registration in StaffProfileModule.
- ProfileCubit/state: load and store reliabilityStats; UI wired to display ReliabilityStatsCard and ReliabilityScoreBar using state values.
- Coverage/shift updates: Added AssignedWorker.hasReview to track if a worker was reviewed; added locationName/locationAddress to ShiftWithWorkers and show location in ShiftHeader; hide rate button if worker.hasReview.
- Clock-in handling: treat backend ALREADY_CLOCKED_IN (409) as idempotent by re-fetching attendance and emitting success when appropriate.
These changes wire backend stats through repository/usecase/cubit to the profile UI and add shift location and review-awareness to client views.
This commit is contained in:
@@ -14,6 +14,10 @@ abstract final class StaffEndpoints {
|
||||
static const ApiEndpoint profileCompletion =
|
||||
ApiEndpoint('/staff/profile-completion');
|
||||
|
||||
/// Staff reliability and performance statistics.
|
||||
static const ApiEndpoint profileStats =
|
||||
ApiEndpoint('/staff/profile/stats');
|
||||
|
||||
/// Staff availability schedule.
|
||||
static const ApiEndpoint availability = ApiEndpoint('/staff/availability');
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ export 'src/entities/profile/accessibility.dart';
|
||||
|
||||
// Ratings
|
||||
export 'src/entities/ratings/staff_rating.dart';
|
||||
export 'src/entities/ratings/staff_reliability_stats.dart';
|
||||
|
||||
// Home
|
||||
export 'src/entities/home/client_dashboard.dart';
|
||||
|
||||
@@ -13,6 +13,7 @@ class AssignedWorker extends Equatable {
|
||||
required this.fullName,
|
||||
required this.status,
|
||||
this.checkInAt,
|
||||
this.hasReview = false,
|
||||
});
|
||||
|
||||
/// Deserialises an [AssignedWorker] from a V2 API JSON map.
|
||||
@@ -25,6 +26,7 @@ class AssignedWorker extends Equatable {
|
||||
checkInAt: json['checkInAt'] != null
|
||||
? DateTime.parse(json['checkInAt'] as String)
|
||||
: null,
|
||||
hasReview: json['hasReview'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,6 +45,9 @@ class AssignedWorker extends Equatable {
|
||||
/// When the worker clocked in (null if not yet).
|
||||
final DateTime? checkInAt;
|
||||
|
||||
/// Whether this worker has already been reviewed for this assignment.
|
||||
final bool hasReview;
|
||||
|
||||
/// Serialises this [AssignedWorker] to a JSON map.
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
@@ -51,6 +56,7 @@ class AssignedWorker extends Equatable {
|
||||
'fullName': fullName,
|
||||
'status': status.toJson(),
|
||||
'checkInAt': checkInAt?.toIso8601String(),
|
||||
'hasReview': hasReview,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,5 +67,6 @@ class AssignedWorker extends Equatable {
|
||||
fullName,
|
||||
status,
|
||||
checkInAt,
|
||||
hasReview,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ class ShiftWithWorkers extends Equatable {
|
||||
required this.requiredWorkerCount,
|
||||
required this.assignedWorkerCount,
|
||||
this.assignedWorkers = const <AssignedWorker>[],
|
||||
this.locationName = '',
|
||||
this.locationAddress = '',
|
||||
});
|
||||
|
||||
/// Deserialises a [ShiftWithWorkers] from a V2 API JSON map.
|
||||
@@ -30,6 +32,8 @@ class ShiftWithWorkers extends Equatable {
|
||||
return ShiftWithWorkers(
|
||||
shiftId: json['shiftId'] as String,
|
||||
roleName: json['roleName'] as String? ?? '',
|
||||
locationName: json['locationName'] as String? ?? '',
|
||||
locationAddress: json['locationAddress'] as String? ?? '',
|
||||
timeRange: TimeRange.fromJson(json['timeRange'] as Map<String, dynamic>),
|
||||
requiredWorkerCount: (json['requiredWorkerCount'] as num).toInt(),
|
||||
assignedWorkerCount: (json['assignedWorkerCount'] as num).toInt(),
|
||||
@@ -55,11 +59,19 @@ class ShiftWithWorkers extends Equatable {
|
||||
/// List of assigned workers with their statuses.
|
||||
final List<AssignedWorker> assignedWorkers;
|
||||
|
||||
/// Location or hub name for this shift.
|
||||
final String locationName;
|
||||
|
||||
/// Street address for this shift.
|
||||
final String locationAddress;
|
||||
|
||||
/// Serialises this [ShiftWithWorkers] to a JSON map.
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
'shiftId': shiftId,
|
||||
'roleName': roleName,
|
||||
'locationName': locationName,
|
||||
'locationAddress': locationAddress,
|
||||
'timeRange': timeRange.toJson(),
|
||||
'requiredWorkerCount': requiredWorkerCount,
|
||||
'assignedWorkerCount': assignedWorkerCount,
|
||||
@@ -76,5 +88,7 @@ class ShiftWithWorkers extends Equatable {
|
||||
requiredWorkerCount,
|
||||
assignedWorkerCount,
|
||||
assignedWorkers,
|
||||
locationName,
|
||||
locationAddress,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Aggregated reliability and performance statistics for a staff member.
|
||||
///
|
||||
/// Returned by `GET /staff/profile/stats`.
|
||||
class StaffReliabilityStats extends Equatable {
|
||||
/// Creates a [StaffReliabilityStats] instance.
|
||||
const StaffReliabilityStats({
|
||||
required this.staffId,
|
||||
this.totalShifts = 0,
|
||||
this.averageRating = 0,
|
||||
this.ratingCount = 0,
|
||||
this.onTimeRate = 0,
|
||||
this.noShowCount = 0,
|
||||
this.cancellationCount = 0,
|
||||
this.reliabilityScore = 0,
|
||||
});
|
||||
|
||||
/// Deserialises from a V2 API JSON map.
|
||||
factory StaffReliabilityStats.fromJson(Map<String, dynamic> json) {
|
||||
return StaffReliabilityStats(
|
||||
staffId: json['staffId'] as String,
|
||||
totalShifts: (json['totalShifts'] as num?)?.toInt() ?? 0,
|
||||
averageRating: (json['averageRating'] as num?)?.toDouble() ?? 0,
|
||||
ratingCount: (json['ratingCount'] as num?)?.toInt() ?? 0,
|
||||
onTimeRate: (json['onTimeRate'] as num?)?.toDouble() ?? 0,
|
||||
noShowCount: (json['noShowCount'] as num?)?.toInt() ?? 0,
|
||||
cancellationCount: (json['cancellationCount'] as num?)?.toInt() ?? 0,
|
||||
reliabilityScore: (json['reliabilityScore'] as num?)?.toDouble() ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
/// The staff member's unique identifier.
|
||||
final String staffId;
|
||||
|
||||
/// Total completed shifts.
|
||||
final int totalShifts;
|
||||
|
||||
/// Average rating from client reviews (0-5).
|
||||
final double averageRating;
|
||||
|
||||
/// Number of ratings received.
|
||||
final int ratingCount;
|
||||
|
||||
/// Percentage of shifts clocked in on time (0-100).
|
||||
final double onTimeRate;
|
||||
|
||||
/// Number of no-show incidents.
|
||||
final int noShowCount;
|
||||
|
||||
/// Number of worker-initiated cancellations.
|
||||
final int cancellationCount;
|
||||
|
||||
/// Composite reliability score (0-100).
|
||||
///
|
||||
/// Weighted: 45% on-time rate + 35% completion rate + 20% rating score.
|
||||
final double reliabilityScore;
|
||||
|
||||
/// Serialises to a JSON map.
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
'staffId': staffId,
|
||||
'totalShifts': totalShifts,
|
||||
'averageRating': averageRating,
|
||||
'ratingCount': ratingCount,
|
||||
'onTimeRate': onTimeRate,
|
||||
'noShowCount': noShowCount,
|
||||
'cancellationCount': cancellationCount,
|
||||
'reliabilityScore': reliabilityScore,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[
|
||||
staffId,
|
||||
totalShifts,
|
||||
averageRating,
|
||||
ratingCount,
|
||||
onTimeRate,
|
||||
noShowCount,
|
||||
cancellationCount,
|
||||
reliabilityScore,
|
||||
];
|
||||
}
|
||||
@@ -161,6 +161,7 @@ class _CoverageShiftListState extends State<CoverageShiftList> {
|
||||
children: <Widget>[
|
||||
ShiftHeader(
|
||||
title: shift.roleName,
|
||||
locationName: shift.locationName,
|
||||
startTime: _formatTime(shift.timeRange.startsAt),
|
||||
current: shift.assignedWorkerCount,
|
||||
total: shift.requiredWorkerCount,
|
||||
@@ -226,9 +227,10 @@ class _CoverageShiftListState extends State<CoverageShiftList> {
|
||||
worker: worker,
|
||||
shiftStartTime: _formatTime(shift.timeRange.startsAt),
|
||||
showRateButton:
|
||||
worker.status == AssignmentStatus.checkedIn ||
|
||||
worker.status == AssignmentStatus.checkedOut ||
|
||||
worker.status == AssignmentStatus.completed,
|
||||
!worker.hasReview &&
|
||||
(worker.status == AssignmentStatus.checkedIn ||
|
||||
worker.status == AssignmentStatus.checkedOut ||
|
||||
worker.status == AssignmentStatus.completed),
|
||||
showCancelButton:
|
||||
DateTime.now().isAfter(shift.timeRange.startsAt) &&
|
||||
(worker.status == AssignmentStatus.noShow ||
|
||||
|
||||
@@ -21,6 +21,7 @@ class ShiftHeader extends StatelessWidget {
|
||||
required this.lateCount,
|
||||
required this.isExpanded,
|
||||
required this.onToggle,
|
||||
this.locationName,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -57,6 +58,9 @@ class ShiftHeader extends StatelessWidget {
|
||||
/// Callback invoked when the header is tapped to expand or collapse.
|
||||
final VoidCallback onToggle;
|
||||
|
||||
/// Optional location or hub name for the shift.
|
||||
final String? locationName;
|
||||
|
||||
/// Returns the status colour based on [coveragePercent].
|
||||
///
|
||||
/// Green for >= 100 %, yellow for >= 80 %, red otherwise.
|
||||
@@ -110,6 +114,29 @@ class ShiftHeader extends StatelessWidget {
|
||||
title,
|
||||
style: UiTypography.body1b.textPrimary,
|
||||
),
|
||||
if (locationName != null &&
|
||||
locationName!.isNotEmpty) ...<Widget>[
|
||||
const SizedBox(height: 2),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Icon(
|
||||
UiIcons.mapPin,
|
||||
size: 10,
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: Text(
|
||||
locationName!,
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
|
||||
@@ -228,12 +228,20 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState>
|
||||
event: event,
|
||||
activeShiftId: newStatus.activeShiftId,
|
||||
);
|
||||
} on AppException catch (_) {
|
||||
// The clock-in API call failed. Re-fetch attendance status to
|
||||
// reconcile: if the worker is already clocked in (e.g. duplicate
|
||||
// session from Postgres constraint 23505), treat it as success.
|
||||
} on AppException catch (e) {
|
||||
// The backend returns 409 ALREADY_CLOCKED_IN when the worker has
|
||||
// an active attendance session. This is a normal idempotency
|
||||
// signal — re-fetch the authoritative status and emit success
|
||||
// without surfacing an error snackbar.
|
||||
final bool isAlreadyClockedIn =
|
||||
e is ApiException && e.apiCode == 'ALREADY_CLOCKED_IN';
|
||||
|
||||
// Re-fetch attendance status to reconcile local state with
|
||||
// the backend (handles both ALREADY_CLOCKED_IN and legacy
|
||||
// Postgres constraint 23505 duplicates).
|
||||
final AttendanceStatus currentStatus = await _getAttendanceStatus();
|
||||
if (currentStatus.isClockedIn) {
|
||||
|
||||
if (isAlreadyClockedIn || currentStatus.isClockedIn) {
|
||||
emit(state.copyWith(
|
||||
status: ClockInStatus.success,
|
||||
attendance: currentStatus,
|
||||
|
||||
@@ -31,6 +31,15 @@ class ProfileRepositoryImpl implements ProfileRepositoryInterface {
|
||||
return ProfileSectionStatus.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StaffReliabilityStats> getReliabilityStats() async {
|
||||
final ApiResponse response =
|
||||
await _api.get(StaffEndpoints.profileStats);
|
||||
final Map<String, dynamic> json =
|
||||
response.data as Map<String, dynamic>;
|
||||
return StaffReliabilityStats.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> signOut() async {
|
||||
await _api.post(AuthEndpoints.signOut);
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
/// Abstract interface for the staff profile repository.
|
||||
///
|
||||
/// Defines the contract for fetching staff profile data,
|
||||
/// section completion statuses, and signing out.
|
||||
/// section completion statuses, reliability stats, and signing out.
|
||||
abstract interface class ProfileRepositoryInterface {
|
||||
/// Fetches the staff profile from the backend.
|
||||
Future<Staff> getStaffProfile();
|
||||
@@ -11,6 +11,9 @@ abstract interface class ProfileRepositoryInterface {
|
||||
/// Fetches the profile section completion statuses.
|
||||
Future<ProfileSectionStatus> getProfileSections();
|
||||
|
||||
/// Fetches reliability and performance statistics for the staff member.
|
||||
Future<StaffReliabilityStats> getReliabilityStats();
|
||||
|
||||
/// Signs out the current user.
|
||||
Future<void> signOut();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
import 'package:staff_profile/src/domain/repositories/profile_repository_interface.dart';
|
||||
|
||||
/// Use case for retrieving the staff member's reliability statistics.
|
||||
class GetReliabilityStatsUseCase
|
||||
implements NoInputUseCase<StaffReliabilityStats> {
|
||||
/// Creates a [GetReliabilityStatsUseCase] with the required [repository].
|
||||
GetReliabilityStatsUseCase(this._repository);
|
||||
|
||||
final ProfileRepositoryInterface _repository;
|
||||
|
||||
@override
|
||||
Future<StaffReliabilityStats> call() {
|
||||
return _repository.getReliabilityStats();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
import 'package:staff_profile/src/domain/usecases/get_profile_sections_usecase.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/get_reliability_stats_usecase.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/get_staff_profile_usecase.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/sign_out_usecase.dart';
|
||||
import 'package:staff_profile/src/presentation/blocs/profile_state.dart';
|
||||
@@ -10,21 +11,24 @@ import 'package:staff_profile/src/presentation/blocs/profile_state.dart';
|
||||
/// Cubit for managing the Profile feature state.
|
||||
///
|
||||
/// Delegates all data fetching to use cases, following Clean Architecture.
|
||||
/// Loads the staff profile and section completion statuses in a single flow.
|
||||
/// Loads the staff profile, section statuses, and reliability stats.
|
||||
class ProfileCubit extends Cubit<ProfileState>
|
||||
with BlocErrorHandler<ProfileState> {
|
||||
/// Creates a [ProfileCubit] with the required use cases.
|
||||
ProfileCubit({
|
||||
required GetStaffProfileUseCase getStaffProfileUseCase,
|
||||
required GetProfileSectionsUseCase getProfileSectionsUseCase,
|
||||
required GetReliabilityStatsUseCase getReliabilityStatsUseCase,
|
||||
required SignOutUseCase signOutUseCase,
|
||||
}) : _getStaffProfileUseCase = getStaffProfileUseCase,
|
||||
_getProfileSectionsUseCase = getProfileSectionsUseCase,
|
||||
_getReliabilityStatsUseCase = getReliabilityStatsUseCase,
|
||||
_signOutUseCase = signOutUseCase,
|
||||
super(const ProfileState());
|
||||
|
||||
final GetStaffProfileUseCase _getStaffProfileUseCase;
|
||||
final GetProfileSectionsUseCase _getProfileSectionsUseCase;
|
||||
final GetReliabilityStatsUseCase _getReliabilityStatsUseCase;
|
||||
final SignOutUseCase _signOutUseCase;
|
||||
|
||||
/// Loads the staff member's profile.
|
||||
@@ -62,6 +66,19 @@ class ProfileCubit extends Cubit<ProfileState>
|
||||
);
|
||||
}
|
||||
|
||||
/// Loads reliability and performance statistics for the staff member.
|
||||
Future<void> loadReliabilityStats() async {
|
||||
await handleError(
|
||||
emit: emit,
|
||||
action: () async {
|
||||
final StaffReliabilityStats stats =
|
||||
await _getReliabilityStatsUseCase();
|
||||
emit(state.copyWith(reliabilityStats: stats));
|
||||
},
|
||||
onError: (String _) => state,
|
||||
);
|
||||
}
|
||||
|
||||
/// Signs out the current user.
|
||||
Future<void> signOut() async {
|
||||
if (state.status == ProfileStatus.loading) {
|
||||
|
||||
@@ -28,6 +28,7 @@ class ProfileState extends Equatable {
|
||||
const ProfileState({
|
||||
this.status = ProfileStatus.initial,
|
||||
this.profile,
|
||||
this.reliabilityStats,
|
||||
this.errorMessage,
|
||||
this.personalInfoComplete,
|
||||
this.emergencyContactsComplete,
|
||||
@@ -37,40 +38,45 @@ class ProfileState extends Equatable {
|
||||
this.documentsComplete,
|
||||
this.certificatesComplete,
|
||||
});
|
||||
/// Current status of the profile feature
|
||||
|
||||
/// Current status of the profile feature.
|
||||
final ProfileStatus status;
|
||||
|
||||
/// The staff member's profile object (null if not loaded)
|
||||
/// The staff member's profile object (null if not loaded).
|
||||
final Staff? profile;
|
||||
|
||||
/// Error message if status is error
|
||||
/// Reliability and performance statistics (null if not loaded).
|
||||
final StaffReliabilityStats? reliabilityStats;
|
||||
|
||||
/// Error message if status is error.
|
||||
final String? errorMessage;
|
||||
|
||||
/// Whether personal information is complete
|
||||
/// Whether personal information is complete.
|
||||
final bool? personalInfoComplete;
|
||||
|
||||
/// Whether emergency contacts are complete
|
||||
/// Whether emergency contacts are complete.
|
||||
final bool? emergencyContactsComplete;
|
||||
|
||||
/// Whether experience information is complete
|
||||
/// Whether experience information is complete.
|
||||
final bool? experienceComplete;
|
||||
|
||||
/// Whether tax forms are complete
|
||||
/// Whether tax forms are complete.
|
||||
final bool? taxFormsComplete;
|
||||
|
||||
/// Whether attire options are complete
|
||||
/// Whether attire options are complete.
|
||||
final bool? attireComplete;
|
||||
|
||||
/// Whether documents are complete
|
||||
/// Whether documents are complete.
|
||||
final bool? documentsComplete;
|
||||
|
||||
/// Whether certificates are complete
|
||||
/// Whether certificates are complete.
|
||||
final bool? certificatesComplete;
|
||||
|
||||
/// Creates a copy of this state with updated values.
|
||||
ProfileState copyWith({
|
||||
ProfileStatus? status,
|
||||
Staff? profile,
|
||||
StaffReliabilityStats? reliabilityStats,
|
||||
String? errorMessage,
|
||||
bool? personalInfoComplete,
|
||||
bool? emergencyContactsComplete,
|
||||
@@ -83,6 +89,7 @@ class ProfileState extends Equatable {
|
||||
return ProfileState(
|
||||
status: status ?? this.status,
|
||||
profile: profile ?? this.profile,
|
||||
reliabilityStats: reliabilityStats ?? this.reliabilityStats,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
personalInfoComplete: personalInfoComplete ?? this.personalInfoComplete,
|
||||
emergencyContactsComplete: emergencyContactsComplete ?? this.emergencyContactsComplete,
|
||||
@@ -98,6 +105,7 @@ class ProfileState extends Equatable {
|
||||
List<Object?> get props => <Object?>[
|
||||
status,
|
||||
profile,
|
||||
reliabilityStats,
|
||||
errorMessage,
|
||||
personalInfoComplete,
|
||||
emergencyContactsComplete,
|
||||
|
||||
@@ -37,10 +37,11 @@ class StaffProfilePage extends StatelessWidget {
|
||||
value: cubit,
|
||||
child: BlocConsumer<ProfileCubit, ProfileState>(
|
||||
listener: (BuildContext context, ProfileState state) {
|
||||
// Load section statuses when profile loads successfully
|
||||
// Load section statuses and reliability stats when profile loads
|
||||
if (state.status == ProfileStatus.loaded &&
|
||||
state.personalInfoComplete == null) {
|
||||
cubit.loadSectionStatuses();
|
||||
cubit.loadReliabilityStats();
|
||||
}
|
||||
|
||||
if (state.status == ProfileStatus.signedOut) {
|
||||
@@ -100,16 +101,16 @@ class StaffProfilePage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
// Reliability Stats
|
||||
ReliabilityStatsCard(
|
||||
totalShifts: 0,
|
||||
averageRating: profile.averageRating,
|
||||
onTimeRate: 0,
|
||||
noShowCount: 0,
|
||||
cancellationCount: 0,
|
||||
totalShifts: state.reliabilityStats?.totalShifts,
|
||||
averageRating: state.reliabilityStats?.averageRating,
|
||||
onTimeRate: state.reliabilityStats?.onTimeRate.round(),
|
||||
noShowCount: state.reliabilityStats?.noShowCount,
|
||||
cancellationCount: state.reliabilityStats?.cancellationCount,
|
||||
),
|
||||
|
||||
// Reliability Score Bar
|
||||
const ReliabilityScoreBar(
|
||||
reliabilityScore: 0,
|
||||
ReliabilityScoreBar(
|
||||
reliabilityScore: state.reliabilityStats?.reliabilityScore.round(),
|
||||
),
|
||||
|
||||
// Ordered sections
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:staff_profile/src/data/repositories/profile_repository_impl.dart';
|
||||
import 'package:staff_profile/src/domain/repositories/profile_repository_interface.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/get_profile_sections_usecase.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/get_reliability_stats_usecase.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/get_staff_profile_usecase.dart';
|
||||
import 'package:staff_profile/src/domain/usecases/sign_out_usecase.dart';
|
||||
import 'package:staff_profile/src/presentation/blocs/profile_cubit.dart';
|
||||
@@ -44,12 +45,18 @@ class StaffProfileModule extends Module {
|
||||
i.get<ProfileRepositoryInterface>(),
|
||||
),
|
||||
);
|
||||
i.addLazySingleton<GetReliabilityStatsUseCase>(
|
||||
() => GetReliabilityStatsUseCase(
|
||||
i.get<ProfileRepositoryInterface>(),
|
||||
),
|
||||
);
|
||||
|
||||
// Cubit
|
||||
i.addLazySingleton<ProfileCubit>(
|
||||
() => ProfileCubit(
|
||||
getStaffProfileUseCase: i.get<GetStaffProfileUseCase>(),
|
||||
getProfileSectionsUseCase: i.get<GetProfileSectionsUseCase>(),
|
||||
getReliabilityStatsUseCase: i.get<GetReliabilityStatsUseCase>(),
|
||||
signOutUseCase: i.get<SignOutUseCase>(),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user