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

@@ -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,
};
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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();