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:
@@ -13,10 +13,16 @@ class TimeSlot extends Equatable {
|
||||
});
|
||||
|
||||
/// Deserialises from a JSON map inside the availability slots array.
|
||||
///
|
||||
/// Supports both V2 API keys (`start`/`end`) and legacy keys
|
||||
/// (`startTime`/`endTime`).
|
||||
factory TimeSlot.fromJson(Map<String, dynamic> json) {
|
||||
return TimeSlot(
|
||||
startTime: json['startTime'] as String? ?? '00:00',
|
||||
endTime: json['endTime'] as String? ?? '00:00',
|
||||
startTime: json['start'] as String? ??
|
||||
json['startTime'] as String? ??
|
||||
'00:00',
|
||||
endTime:
|
||||
json['end'] as String? ?? json['endTime'] as String? ?? '00:00',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,11 +32,11 @@ class TimeSlot extends Equatable {
|
||||
/// End time in `HH:MM` format.
|
||||
final String endTime;
|
||||
|
||||
/// Serialises to JSON.
|
||||
/// Serialises to JSON matching the V2 API contract.
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
'startTime': startTime,
|
||||
'endTime': endTime,
|
||||
'start': startTime,
|
||||
'end': endTime,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
import '../benefits/benefit.dart';
|
||||
import '../shifts/assigned_shift.dart';
|
||||
import '../shifts/open_shift.dart';
|
||||
import '../shifts/today_shift.dart';
|
||||
|
||||
/// Staff dashboard data with shifts and benefits overview.
|
||||
///
|
||||
@@ -9,9 +12,9 @@ class StaffDashboard extends Equatable {
|
||||
/// Creates a [StaffDashboard] instance.
|
||||
const StaffDashboard({
|
||||
required this.staffName,
|
||||
this.todaysShifts = const <Map<String, dynamic>>[],
|
||||
this.tomorrowsShifts = const <Map<String, dynamic>>[],
|
||||
this.recommendedShifts = const <Map<String, dynamic>>[],
|
||||
this.todaysShifts = const <TodayShift>[],
|
||||
this.tomorrowsShifts = const <AssignedShift>[],
|
||||
this.recommendedShifts = const <OpenShift>[],
|
||||
this.benefits = const <Benefit>[],
|
||||
});
|
||||
|
||||
@@ -25,10 +28,19 @@ class StaffDashboard extends Equatable {
|
||||
: const <Benefit>[];
|
||||
|
||||
return StaffDashboard(
|
||||
staffName: json['staffName'] as String,
|
||||
todaysShifts: _castShiftList(json['todaysShifts']),
|
||||
tomorrowsShifts: _castShiftList(json['tomorrowsShifts']),
|
||||
recommendedShifts: _castShiftList(json['recommendedShifts']),
|
||||
staffName: json['staffName'] as String? ?? '',
|
||||
todaysShifts: _parseList<TodayShift>(
|
||||
json['todaysShifts'],
|
||||
TodayShift.fromJson,
|
||||
),
|
||||
tomorrowsShifts: _parseList<AssignedShift>(
|
||||
json['tomorrowsShifts'],
|
||||
AssignedShift.fromJson,
|
||||
),
|
||||
recommendedShifts: _parseList<OpenShift>(
|
||||
json['recommendedShifts'],
|
||||
OpenShift.fromJson,
|
||||
),
|
||||
benefits: benefitsList,
|
||||
);
|
||||
}
|
||||
@@ -37,13 +49,13 @@ class StaffDashboard extends Equatable {
|
||||
final String staffName;
|
||||
|
||||
/// Shifts assigned for today.
|
||||
final List<Map<String, dynamic>> todaysShifts;
|
||||
final List<TodayShift> todaysShifts;
|
||||
|
||||
/// Shifts assigned for tomorrow.
|
||||
final List<Map<String, dynamic>> tomorrowsShifts;
|
||||
final List<AssignedShift> tomorrowsShifts;
|
||||
|
||||
/// Recommended open shifts.
|
||||
final List<Map<String, dynamic>> recommendedShifts;
|
||||
final List<OpenShift> recommendedShifts;
|
||||
|
||||
/// Active benefits.
|
||||
final List<Benefit> benefits;
|
||||
@@ -52,21 +64,27 @@ class StaffDashboard extends Equatable {
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
'staffName': staffName,
|
||||
'todaysShifts': todaysShifts,
|
||||
'tomorrowsShifts': tomorrowsShifts,
|
||||
'recommendedShifts': recommendedShifts,
|
||||
'todaysShifts':
|
||||
todaysShifts.map((TodayShift s) => s.toJson()).toList(),
|
||||
'tomorrowsShifts':
|
||||
tomorrowsShifts.map((AssignedShift s) => s.toJson()).toList(),
|
||||
'recommendedShifts':
|
||||
recommendedShifts.map((OpenShift s) => s.toJson()).toList(),
|
||||
'benefits': benefits.map((Benefit b) => b.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
static List<Map<String, dynamic>> _castShiftList(dynamic raw) {
|
||||
/// Safely parses a JSON list into a typed [List].
|
||||
static List<T> _parseList<T>(
|
||||
dynamic raw,
|
||||
T Function(Map<String, dynamic>) fromJson,
|
||||
) {
|
||||
if (raw is List) {
|
||||
return raw
|
||||
.map((dynamic e) =>
|
||||
Map<String, dynamic>.from(e as Map<dynamic, dynamic>))
|
||||
.map((dynamic e) => fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
return const <Map<String, dynamic>>[];
|
||||
return <T>[];
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -17,6 +17,7 @@ class StaffPersonalInfo extends Equatable {
|
||||
this.skills = const <String>[],
|
||||
this.email,
|
||||
this.phone,
|
||||
this.photoUrl,
|
||||
});
|
||||
|
||||
/// Deserialises a [StaffPersonalInfo] from the V2 API JSON response.
|
||||
@@ -32,6 +33,7 @@ class StaffPersonalInfo extends Equatable {
|
||||
skills: _parseStringList(json['skills']),
|
||||
email: json['email'] as String?,
|
||||
phone: json['phone'] as String?,
|
||||
photoUrl: json['photoUrl'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,6 +67,9 @@ class StaffPersonalInfo extends Equatable {
|
||||
/// Contact phone number.
|
||||
final String? phone;
|
||||
|
||||
/// URL of the staff member's profile photo.
|
||||
final String? photoUrl;
|
||||
|
||||
/// Serialises this [StaffPersonalInfo] to a JSON map.
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
@@ -78,6 +83,7 @@ class StaffPersonalInfo extends Equatable {
|
||||
'skills': skills,
|
||||
'email': email,
|
||||
'phone': phone,
|
||||
'photoUrl': photoUrl,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,6 +99,7 @@ class StaffPersonalInfo extends Equatable {
|
||||
skills,
|
||||
email,
|
||||
phone,
|
||||
photoUrl,
|
||||
];
|
||||
|
||||
/// Parses a dynamic value into a list of strings.
|
||||
|
||||
@@ -1,31 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Lifecycle status of a staff account in V2.
|
||||
enum StaffStatus {
|
||||
/// Staff is active and eligible for work.
|
||||
active,
|
||||
|
||||
/// Staff has been invited but has not completed onboarding.
|
||||
invited,
|
||||
|
||||
/// Staff account has been deactivated.
|
||||
inactive,
|
||||
|
||||
/// Staff account has been blocked by an admin.
|
||||
blocked,
|
||||
}
|
||||
|
||||
/// Onboarding progress of a staff member.
|
||||
enum OnboardingStatus {
|
||||
/// Onboarding has not started.
|
||||
pending,
|
||||
|
||||
/// Onboarding is in progress.
|
||||
inProgress,
|
||||
|
||||
/// Onboarding is complete.
|
||||
completed,
|
||||
}
|
||||
import 'package:krow_domain/krow_domain.dart' show OnboardingStatus, StaffStatus;
|
||||
|
||||
/// Represents a worker profile in the KROW platform.
|
||||
///
|
||||
@@ -63,9 +38,9 @@ class Staff extends Equatable {
|
||||
fullName: json['fullName'] as String,
|
||||
email: json['email'] as String?,
|
||||
phone: json['phone'] as String?,
|
||||
status: _parseStaffStatus(json['status'] as String?),
|
||||
status: StaffStatus.fromJson(json['status'] as String?),
|
||||
primaryRole: json['primaryRole'] as String?,
|
||||
onboardingStatus: _parseOnboardingStatus(json['onboardingStatus'] as String?),
|
||||
onboardingStatus: OnboardingStatus.fromJson(json['onboardingStatus'] as String?),
|
||||
averageRating: _parseDouble(json['averageRating']),
|
||||
ratingCount: (json['ratingCount'] as num?)?.toInt() ?? 0,
|
||||
metadata: (json['metadata'] as Map<String, dynamic>?) ?? const <String, dynamic>{},
|
||||
@@ -137,9 +112,9 @@ class Staff extends Equatable {
|
||||
'fullName': fullName,
|
||||
'email': email,
|
||||
'phone': phone,
|
||||
'status': status.name.toUpperCase(),
|
||||
'status': status.toJson(),
|
||||
'primaryRole': primaryRole,
|
||||
'onboardingStatus': onboardingStatus.name.toUpperCase(),
|
||||
'onboardingStatus': onboardingStatus.toJson(),
|
||||
'averageRating': averageRating,
|
||||
'ratingCount': ratingCount,
|
||||
'metadata': metadata,
|
||||
@@ -172,36 +147,6 @@ class Staff extends Equatable {
|
||||
updatedAt,
|
||||
];
|
||||
|
||||
/// Parses a status string into a [StaffStatus].
|
||||
static StaffStatus _parseStaffStatus(String? value) {
|
||||
switch (value?.toUpperCase()) {
|
||||
case 'ACTIVE':
|
||||
return StaffStatus.active;
|
||||
case 'INVITED':
|
||||
return StaffStatus.invited;
|
||||
case 'INACTIVE':
|
||||
return StaffStatus.inactive;
|
||||
case 'BLOCKED':
|
||||
return StaffStatus.blocked;
|
||||
default:
|
||||
return StaffStatus.active;
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses an onboarding status string into an [OnboardingStatus].
|
||||
static OnboardingStatus _parseOnboardingStatus(String? value) {
|
||||
switch (value?.toUpperCase()) {
|
||||
case 'PENDING':
|
||||
return OnboardingStatus.pending;
|
||||
case 'IN_PROGRESS':
|
||||
return OnboardingStatus.inProgress;
|
||||
case 'COMPLETED':
|
||||
return OnboardingStatus.completed;
|
||||
default:
|
||||
return OnboardingStatus.pending;
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely parses a numeric value to double.
|
||||
static double _parseDouble(Object? value) {
|
||||
if (value is num) return value.toDouble();
|
||||
|
||||
Reference in New Issue
Block a user