Enhance staff profile management by updating data structures and repository implementation
- Added new fields to the Staff entity for better profile details. - Updated ProfileRepositoryImpl to fetch staff profiles using a connector. - Refactored GetProfileUseCase to map staff data to UI entities. - Improved dependency injection in StaffProfileModule. - Cleaned up unused mock data references and streamlined profile page logic.
This commit is contained in:
@@ -29,17 +29,21 @@ enum StaffStatus {
|
||||
/// Contains all personal and professional details of a staff member.
|
||||
/// Linked to a [User] via [authProviderId].
|
||||
class Staff extends Equatable {
|
||||
|
||||
const Staff({
|
||||
required this.id,
|
||||
required this.authProviderId,
|
||||
required this.name,
|
||||
required this.email,
|
||||
this.phone,
|
||||
this.avatar,
|
||||
required this.status,
|
||||
this.address,
|
||||
this.avatar,
|
||||
this.livePhoto,
|
||||
this.totalShifts,
|
||||
this.averageRating,
|
||||
this.onTimeRate,
|
||||
this.noShowCount,
|
||||
this.cancellationCount,
|
||||
this.reliabilityScore,
|
||||
});
|
||||
/// Unique identifier for the staff profile.
|
||||
final String id;
|
||||
@@ -56,17 +60,34 @@ class Staff extends Equatable {
|
||||
/// Contact phone number.
|
||||
final String? phone;
|
||||
|
||||
/// Profile picture URL.
|
||||
final String? avatar;
|
||||
|
||||
/// Current workflow status of the staff member.
|
||||
final StaffStatus status;
|
||||
|
||||
/// Physical address string.
|
||||
/// The user's physical address.
|
||||
///
|
||||
/// Can be used for location-based job matching.
|
||||
final String? address;
|
||||
|
||||
/// URL to the avatar image.
|
||||
final String? avatar;
|
||||
/// The total number of shifts completed.
|
||||
final int? totalShifts;
|
||||
|
||||
/// URL to a verified live photo for identity verification.
|
||||
final String? livePhoto;
|
||||
/// The average rating from businesses.
|
||||
final double? averageRating;
|
||||
|
||||
/// The percentage of shifts arrived on time.
|
||||
final int? onTimeRate;
|
||||
|
||||
/// The number of no-shows.
|
||||
final int? noShowCount;
|
||||
|
||||
/// The number of cancellations within 24h.
|
||||
final int? cancellationCount;
|
||||
|
||||
/// The reliability score (0-100).
|
||||
final int? reliabilityScore;
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[
|
||||
@@ -75,9 +96,14 @@ class Staff extends Equatable {
|
||||
name,
|
||||
email,
|
||||
phone,
|
||||
avatar,
|
||||
status,
|
||||
address,
|
||||
avatar,
|
||||
livePhoto,
|
||||
totalShifts,
|
||||
averageRating,
|
||||
onTimeRate,
|
||||
noShowCount,
|
||||
cancellationCount,
|
||||
reliabilityScore,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class ClientCreateOrderModule extends Module {
|
||||
i.addLazySingleton(CreateRapidOrderUseCase.new);
|
||||
|
||||
// BLoCs
|
||||
i.addSingleton<ClientCreateOrderBloc>(ClientCreateOrderBloc.new);
|
||||
i.add<ClientCreateOrderBloc>(ClientCreateOrderBloc.new);
|
||||
i.add<RapidOrderBloc>(RapidOrderBloc.new);
|
||||
i.add<OneTimeOrderBloc>(
|
||||
() => OneTimeOrderBloc(
|
||||
|
||||
@@ -14,22 +14,49 @@ import '../../domain/repositories/profile_repository.dart';
|
||||
/// Currently uses [ProfileRepositoryMock] from data_connect.
|
||||
/// When Firebase Data Connect is ready, this will be swapped with a real implementation.
|
||||
class ProfileRepositoryImpl implements ProfileRepositoryInterface {
|
||||
final ProfileRepositoryMock _dataConnectRepository;
|
||||
|
||||
/// Creates a [ProfileRepositoryImpl].
|
||||
///
|
||||
/// Requires a [ProfileRepositoryMock] from the data_connect package.
|
||||
const ProfileRepositoryImpl(this._dataConnectRepository);
|
||||
/// Requires a [ExampleConnector] from the data_connect package.
|
||||
const ProfileRepositoryImpl({required this.connector});
|
||||
|
||||
/// The Data Connect connector used for data operations.
|
||||
final ExampleConnector connector;
|
||||
|
||||
@override
|
||||
Future<Staff> getStaffProfile(String userId) {
|
||||
// Delegate directly to data_connect - no business logic here
|
||||
return _dataConnectRepository.getStaffProfile(userId);
|
||||
Future<Staff> getStaffProfile(String userId) async {
|
||||
// ignore: always_specify_types
|
||||
final response = await connector.getStaffByUserId(userId: userId).execute();
|
||||
|
||||
if (response.data.staffs.isEmpty) {
|
||||
// TODO: Handle user not found properly with domain exception
|
||||
throw Exception('Staff not found');
|
||||
}
|
||||
|
||||
final GetStaffByUserIdStaffs rawStaff = response.data.staffs.first;
|
||||
|
||||
// Map the raw data connect object to the Domain Entity
|
||||
return Staff(
|
||||
id: rawStaff.id,
|
||||
authProviderId: rawStaff.userId,
|
||||
name: rawStaff.fullName,
|
||||
email: rawStaff.email ?? '',
|
||||
phone: rawStaff.phone,
|
||||
avatar: rawStaff.photoUrl,
|
||||
status: StaffStatus.active,
|
||||
address: null,
|
||||
totalShifts: rawStaff.totalShifts,
|
||||
averageRating: rawStaff.averageRating,
|
||||
onTimeRate: rawStaff.onTimeRate,
|
||||
noShowCount: rawStaff.noShowCount,
|
||||
cancellationCount: rawStaff.cancellationCount,
|
||||
reliabilityScore: rawStaff.reliabilityScore,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> signOut() {
|
||||
// Delegate directly to data_connect - no business logic here
|
||||
return _dataConnectRepository.signOut();
|
||||
// TODO: Implement sign out via Auth interface, not profile repository
|
||||
// For now, no-op or delegate if connector has auth
|
||||
return Future.value();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,19 +31,18 @@ class GetProfileUseCase implements UseCase<String, StaffProfileUI> {
|
||||
final staff = await _repository.getStaffProfile(userId);
|
||||
|
||||
// Map to UI entity with additional profile data
|
||||
// TODO: Replace mock data with actual profile statistics from backend
|
||||
return StaffProfileUI(
|
||||
staff: staff,
|
||||
totalShifts: 0,
|
||||
averageRating: 5.0,
|
||||
onTimeRate: 100,
|
||||
noShowCount: 0,
|
||||
cancellationCount: 0,
|
||||
reliabilityScore: 100,
|
||||
totalShifts: staff.totalShifts ?? 0,
|
||||
averageRating: staff.averageRating ?? 5.0,
|
||||
onTimeRate: staff.onTimeRate ?? 0,
|
||||
noShowCount: staff.noShowCount ?? 0,
|
||||
cancellationCount: staff.cancellationCount ?? 0,
|
||||
reliabilityScore: staff.reliabilityScore ?? 100,
|
||||
hasPersonalInfo: staff.phone != null && staff.phone!.isNotEmpty,
|
||||
hasEmergencyContact: false, // TODO: Fetch from backend
|
||||
hasExperience: false, // TODO: Fetch from backend
|
||||
hasAttire: staff.avatar != null,
|
||||
hasAttire: false, // TODO: Check attire items from backend when available
|
||||
hasDocuments: false, // TODO: Fetch from backend
|
||||
hasCertificates: false, // TODO: Fetch from backend
|
||||
hasTaxForms: false, // TODO: Fetch from backend
|
||||
|
||||
@@ -28,8 +28,8 @@ class StaffProfilePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.profile;
|
||||
final cubit = Modular.get<ProfileCubit>();
|
||||
final TranslationsStaffProfileEn i18n = t.staff.profile;
|
||||
final ProfileCubit cubit = Modular.get<ProfileCubit>();
|
||||
|
||||
// Load profile data on first build
|
||||
// TODO: Get actual userId from auth session
|
||||
@@ -40,7 +40,6 @@ class StaffProfilePage extends StatelessWidget {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: UiColors.background,
|
||||
body: BlocBuilder<ProfileCubit, ProfileState>(
|
||||
bloc: cubit,
|
||||
builder: (context, state) {
|
||||
|
||||
@@ -15,19 +15,15 @@ import 'presentation/pages/staff_profile_page.dart';
|
||||
/// following Clean Architecture principles.
|
||||
///
|
||||
/// Dependency flow:
|
||||
/// - Data source (ProfileRepositoryMock) from data_connect package
|
||||
/// - Repository implementation (ProfileRepositoryImpl) delegates to data_connect
|
||||
/// - Use cases depend on repository interface
|
||||
/// - Cubit depends on use cases
|
||||
class StaffProfileModule extends Module {
|
||||
@override
|
||||
void binds(Injector i) {
|
||||
// Data layer - Get mock from data_connect package
|
||||
i.addLazySingleton<ProfileRepositoryMock>(ProfileRepositoryMock.new);
|
||||
|
||||
// Repository implementation - delegates to data_connect
|
||||
i.addLazySingleton<ProfileRepositoryInterface>(
|
||||
() => ProfileRepositoryImpl(i.get<ProfileRepositoryMock>()),
|
||||
() => ProfileRepositoryImpl(connector: ExampleConnector.instance),
|
||||
);
|
||||
|
||||
// Use cases - depend on repository interface
|
||||
@@ -39,8 +35,7 @@ class StaffProfileModule extends Module {
|
||||
);
|
||||
|
||||
// Presentation layer - Cubit depends on use cases
|
||||
// Use addLazySingleton to create a new instance per module lifecycle
|
||||
i.addLazySingleton(
|
||||
i.add<ProfileCubit>(
|
||||
() => ProfileCubit(
|
||||
i.get<GetProfileUseCase>(),
|
||||
i.get<SignOutUseCase>(),
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
/// Export the modular feature definition.
|
||||
export 'src/staff_profile_module.dart';
|
||||
|
||||
Reference in New Issue
Block a user