feat: Integrate ShiftAdapter for mapping application data to Shift entities and update status handling in Coverage and Shifts repositories
This commit is contained in:
@@ -1,10 +1,59 @@
|
|||||||
|
import 'package:intl/intl.dart';
|
||||||
import '../../entities/shifts/shift.dart';
|
import '../../entities/shifts/shift.dart';
|
||||||
|
|
||||||
/// Adapter for Shift related data.
|
/// Adapter for Shift related data.
|
||||||
class ShiftAdapter {
|
class ShiftAdapter {
|
||||||
|
/// Maps application data to a Shift entity.
|
||||||
// Note: Conversion logic will likely live in RepoImpl or here if we pass raw objects.
|
///
|
||||||
// Given we are dealing with generated types that aren't exported by domain,
|
/// This method handles the common mapping logic used across different
|
||||||
// we might put the logic in Repo or make this accept dynamic/Map if strictly required.
|
/// repositories when converting application data from Data Connect to
|
||||||
// For now, placeholders or simple status helpers.
|
/// domain Shift entities.
|
||||||
|
static Shift fromApplicationData({
|
||||||
|
required String shiftId,
|
||||||
|
required String roleId,
|
||||||
|
required String roleName,
|
||||||
|
required String businessName,
|
||||||
|
String? companyLogoUrl,
|
||||||
|
required double costPerHour,
|
||||||
|
String? shiftLocation,
|
||||||
|
required String teamHubName,
|
||||||
|
DateTime? shiftDate,
|
||||||
|
DateTime? startTime,
|
||||||
|
DateTime? endTime,
|
||||||
|
DateTime? createdAt,
|
||||||
|
required String status,
|
||||||
|
String? description,
|
||||||
|
int? durationDays,
|
||||||
|
required int count,
|
||||||
|
int? assigned,
|
||||||
|
String? eventName,
|
||||||
|
bool hasApplied = false,
|
||||||
|
}) {
|
||||||
|
final String orderName = (eventName ?? '').trim().isNotEmpty
|
||||||
|
? eventName!
|
||||||
|
: businessName;
|
||||||
|
final String title = '$roleName - $orderName';
|
||||||
|
|
||||||
|
return Shift(
|
||||||
|
id: shiftId,
|
||||||
|
roleId: roleId,
|
||||||
|
title: title,
|
||||||
|
clientName: businessName,
|
||||||
|
logoUrl: companyLogoUrl,
|
||||||
|
hourlyRate: costPerHour,
|
||||||
|
location: shiftLocation ?? '',
|
||||||
|
locationAddress: teamHubName,
|
||||||
|
date: shiftDate?.toIso8601String() ?? '',
|
||||||
|
startTime: startTime != null ? DateFormat('HH:mm').format(startTime) : '',
|
||||||
|
endTime: endTime != null ? DateFormat('HH:mm').format(endTime) : '',
|
||||||
|
createdDate: createdAt?.toIso8601String() ?? '',
|
||||||
|
status: status,
|
||||||
|
description: description,
|
||||||
|
durationDays: durationDays,
|
||||||
|
requiredSlots: count,
|
||||||
|
filledSlots: assigned ?? 0,
|
||||||
|
hasApplied: hasApplied,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ class CoverageRepositoryImpl implements CoverageRepository {
|
|||||||
case dc.ApplicationStatus.PENDING:
|
case dc.ApplicationStatus.PENDING:
|
||||||
return CoverageWorkerStatus.pending;
|
return CoverageWorkerStatus.pending;
|
||||||
case dc.ApplicationStatus.ACCEPTED:
|
case dc.ApplicationStatus.ACCEPTED:
|
||||||
return CoverageWorkerStatus.accepted;
|
return CoverageWorkerStatus.confirmed;
|
||||||
case dc.ApplicationStatus.REJECTED:
|
case dc.ApplicationStatus.REJECTED:
|
||||||
return CoverageWorkerStatus.rejected;
|
return CoverageWorkerStatus.rejected;
|
||||||
case dc.ApplicationStatus.CONFIRMED:
|
case dc.ApplicationStatus.CONFIRMED:
|
||||||
|
|||||||
@@ -32,28 +32,40 @@ class HomeRepositoryImpl implements HomeRepository {
|
|||||||
|
|
||||||
Future<List<Shift>> _getShiftsForDate(DateTime date) async {
|
Future<List<Shift>> _getShiftsForDate(DateTime date) async {
|
||||||
try {
|
try {
|
||||||
|
final staffId = _currentStaffId;
|
||||||
|
|
||||||
|
// Create start and end timestamps for the target date
|
||||||
|
final DateTime start = DateTime(date.year, date.month, date.day);
|
||||||
|
final DateTime end = DateTime(date.year, date.month, date.day, 23, 59, 59, 999);
|
||||||
|
|
||||||
final response = await ExampleConnector.instance
|
final response = await ExampleConnector.instance
|
||||||
.getApplicationsByStaffId(staffId: _currentStaffId)
|
.getApplicationsByStaffId(staffId: staffId)
|
||||||
|
.dayStart(_toTimestamp(start))
|
||||||
|
.dayEnd(_toTimestamp(end))
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final targetYmd = DateFormat('yyyy-MM-dd').format(date);
|
// Filter for ACCEPTED applications (same logic as shifts_repository_impl)
|
||||||
|
final apps = response.data.applications.where(
|
||||||
return response.data.applications
|
(app) => (app.status is Known && (app.status as Known).value == ApplicationStatus.ACCEPTED) || (app.status is Known && (app.status as Known).value == ApplicationStatus.CONFIRMED)
|
||||||
.where((app) {
|
);
|
||||||
final shiftDate = app.shift.date?.toDate();
|
|
||||||
if (shiftDate == null) return false;
|
final List<Shift> shifts = [];
|
||||||
|
for (final app in apps) {
|
||||||
final isDateMatch = DateFormat('yyyy-MM-dd').format(shiftDate) == targetYmd;
|
shifts.add(_mapApplicationToShift(app));
|
||||||
final isAssigned = app.status is Known && ((app.status as Known).value == ApplicationStatus.ACCEPTED || (app.status as Known).value == ApplicationStatus.CONFIRMED);
|
}
|
||||||
|
|
||||||
return isDateMatch && isAssigned;
|
return shifts;
|
||||||
})
|
|
||||||
.map((app) => _mapApplicationToShift(app))
|
|
||||||
.toList();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timestamp _toTimestamp(DateTime dateTime) {
|
||||||
|
final DateTime utc = dateTime.toUtc();
|
||||||
|
final int seconds = utc.millisecondsSinceEpoch ~/ 1000;
|
||||||
|
final int nanoseconds = (utc.microsecondsSinceEpoch % 1000000) * 1000;
|
||||||
|
return Timestamp(nanoseconds, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Shift>> getRecommendedShifts() async {
|
Future<List<Shift>> getRecommendedShifts() async {
|
||||||
@@ -93,21 +105,26 @@ class HomeRepositoryImpl implements HomeRepository {
|
|||||||
final s = app.shift;
|
final s = app.shift;
|
||||||
final r = app.shiftRole;
|
final r = app.shiftRole;
|
||||||
|
|
||||||
return Shift(
|
return ShiftAdapter.fromApplicationData(
|
||||||
id: s.id,
|
shiftId: s.id,
|
||||||
title: r.role.name,
|
roleId: r.roleId,
|
||||||
clientName: s.order.business.businessName,
|
roleName: r.role.name,
|
||||||
hourlyRate: r.role.costPerHour,
|
businessName: s.order.business.businessName,
|
||||||
location: s.location ?? 'Unknown',
|
companyLogoUrl: s.order.business.companyLogoUrl,
|
||||||
locationAddress: s.location ?? '',
|
costPerHour: r.role.costPerHour,
|
||||||
date: s.date?.toDate().toIso8601String() ?? '',
|
shiftLocation: s.location,
|
||||||
startTime: DateFormat('HH:mm').format(r.startTime?.toDate() ?? DateTime.now()),
|
teamHubName: s.order.teamHub.hubName,
|
||||||
endTime: DateFormat('HH:mm').format(r.endTime?.toDate() ?? DateTime.now()),
|
shiftDate: s.date?.toDate(),
|
||||||
createdDate: app.createdAt?.toDate().toIso8601String() ?? '',
|
startTime: r.startTime?.toDate(),
|
||||||
tipsAvailable: false, // Not in API
|
endTime: r.endTime?.toDate(),
|
||||||
mealProvided: false, // Not in API
|
createdAt: app.createdAt?.toDate(),
|
||||||
managers: [], // Not in this query
|
status: 'confirmed',
|
||||||
description: null,
|
description: s.description,
|
||||||
|
durationDays: s.durationDays,
|
||||||
|
count: r.count,
|
||||||
|
assigned: r.assigned,
|
||||||
|
eventName: s.order.eventName,
|
||||||
|
hasApplied: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,13 +77,42 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper method to map Data Connect application to domain Shift using ShiftAdapter.
|
||||||
|
Shift _mapApplicationToShift(
|
||||||
|
dynamic app,
|
||||||
|
String status, {
|
||||||
|
bool hasApplied = true,
|
||||||
|
}) {
|
||||||
|
return ShiftAdapter.fromApplicationData(
|
||||||
|
shiftId: app.shift.id,
|
||||||
|
roleId: app.shiftRole.roleId,
|
||||||
|
roleName: app.shiftRole.role.name,
|
||||||
|
businessName: app.shift.order.business.businessName,
|
||||||
|
companyLogoUrl: app.shift.order.business.companyLogoUrl,
|
||||||
|
costPerHour: app.shiftRole.role.costPerHour,
|
||||||
|
shiftLocation: app.shift.location,
|
||||||
|
teamHubName: app.shift.order.teamHub.hubName,
|
||||||
|
shiftDate: _toDateTime(app.shift.date),
|
||||||
|
startTime: _toDateTime(app.shiftRole.startTime),
|
||||||
|
endTime: _toDateTime(app.shiftRole.endTime),
|
||||||
|
createdAt: _toDateTime(app.createdAt),
|
||||||
|
status: status,
|
||||||
|
description: app.shift.description,
|
||||||
|
durationDays: app.shift.durationDays,
|
||||||
|
count: app.shiftRole.count,
|
||||||
|
assigned: app.shiftRole.assigned,
|
||||||
|
eventName: app.shift.order.eventName,
|
||||||
|
hasApplied: hasApplied,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Shift>> getMyShifts({
|
Future<List<Shift>> getMyShifts({
|
||||||
required DateTime start,
|
required DateTime start,
|
||||||
required DateTime end,
|
required DateTime end,
|
||||||
}) async {
|
}) async {
|
||||||
return _fetchApplications(
|
return _fetchApplications(
|
||||||
dc.ApplicationStatus.ACCEPTED,
|
[dc.ApplicationStatus.ACCEPTED, dc.ApplicationStatus.CONFIRMED],
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
);
|
);
|
||||||
@@ -91,12 +120,12 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Shift>> getPendingAssignments() async {
|
Future<List<Shift>> getPendingAssignments() async {
|
||||||
return _fetchApplications(dc.ApplicationStatus.PENDING);
|
return _fetchApplications([dc.ApplicationStatus.PENDING]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Shift>> getCancelledShifts() async {
|
Future<List<Shift>> getCancelledShifts() async {
|
||||||
return _fetchApplications(dc.ApplicationStatus.REJECTED);
|
return _fetchApplications([dc.ApplicationStatus.REJECTED]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -112,37 +141,10 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
_shiftToAppIdMap[app.shift.id] = app.id;
|
_shiftToAppIdMap[app.shift.id] = app.id;
|
||||||
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
||||||
|
|
||||||
final String roleName = app.shiftRole.role.name;
|
|
||||||
final String orderName =
|
|
||||||
(app.shift.order.eventName ?? '').trim().isNotEmpty
|
|
||||||
? app.shift.order.eventName!
|
|
||||||
: app.shift.order.business.businessName;
|
|
||||||
final String title = '$roleName - $orderName';
|
|
||||||
final DateTime? shiftDate = _toDateTime(app.shift.date);
|
|
||||||
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
|
|
||||||
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
|
|
||||||
final DateTime? createdDt = _toDateTime(app.createdAt);
|
|
||||||
|
|
||||||
shifts.add(
|
shifts.add(
|
||||||
Shift(
|
_mapApplicationToShift(
|
||||||
id: app.shift.id,
|
app,
|
||||||
roleId: app.shiftRole.roleId,
|
_mapStatus(dc.ApplicationStatus.CHECKED_OUT),
|
||||||
title: title,
|
|
||||||
clientName: app.shift.order.business.businessName,
|
|
||||||
logoUrl: app.shift.order.business.companyLogoUrl,
|
|
||||||
hourlyRate: app.shiftRole.role.costPerHour,
|
|
||||||
location: app.shift.location ?? '',
|
|
||||||
locationAddress: app.shift.order.teamHub.hubName,
|
|
||||||
date: shiftDate?.toIso8601String() ?? '',
|
|
||||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
|
||||||
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
|
||||||
createdDate: createdDt?.toIso8601String() ?? '',
|
|
||||||
status: _mapStatus(dc.ApplicationStatus.CHECKED_OUT),
|
|
||||||
description: app.shift.description,
|
|
||||||
durationDays: app.shift.durationDays,
|
|
||||||
requiredSlots: app.shiftRole.count,
|
|
||||||
filledSlots: app.shiftRole.assigned ?? 0,
|
|
||||||
hasApplied: true,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -153,7 +155,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Shift>> _fetchApplications(
|
Future<List<Shift>> _fetchApplications(
|
||||||
dc.ApplicationStatus status, {
|
List<dc.ApplicationStatus> statuses, {
|
||||||
DateTime? start,
|
DateTime? start,
|
||||||
DateTime? end,
|
DateTime? end,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -167,8 +169,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
}
|
}
|
||||||
final response = await query.execute();
|
final response = await query.execute();
|
||||||
|
|
||||||
|
final statusNames = statuses.map((s) => s.name).toSet();
|
||||||
final apps = response.data.applications.where(
|
final apps = response.data.applications.where(
|
||||||
(app) => app.status.stringValue == status.name,
|
(app) => statusNames.contains(app.status.stringValue),
|
||||||
);
|
);
|
||||||
final List<Shift> shifts = [];
|
final List<Shift> shifts = [];
|
||||||
|
|
||||||
@@ -176,40 +179,12 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
_shiftToAppIdMap[app.shift.id] = app.id;
|
_shiftToAppIdMap[app.shift.id] = app.id;
|
||||||
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
||||||
|
|
||||||
final String roleName = app.shiftRole.role.name;
|
// Use the first matching status for mapping
|
||||||
final String orderName =
|
final matchingStatus = statuses.firstWhere(
|
||||||
(app.shift.order.eventName ?? '').trim().isNotEmpty
|
(s) => s.name == app.status.stringValue,
|
||||||
? app.shift.order.eventName!
|
orElse: () => statuses.first,
|
||||||
: app.shift.order.business.businessName;
|
|
||||||
final String title = '$roleName - $orderName';
|
|
||||||
final DateTime? shiftDate = _toDateTime(app.shift.date);
|
|
||||||
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
|
|
||||||
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
|
|
||||||
final DateTime? createdDt = _toDateTime(app.createdAt);
|
|
||||||
|
|
||||||
// Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED)
|
|
||||||
shifts.add(
|
|
||||||
Shift(
|
|
||||||
id: app.shift.id,
|
|
||||||
roleId: app.shiftRole.roleId,
|
|
||||||
title: title,
|
|
||||||
clientName: app.shift.order.business.businessName,
|
|
||||||
logoUrl: app.shift.order.business.companyLogoUrl,
|
|
||||||
hourlyRate: app.shiftRole.role.costPerHour,
|
|
||||||
location: app.shift.location ?? '',
|
|
||||||
locationAddress: app.shift.order.teamHub.hubName,
|
|
||||||
date: shiftDate?.toIso8601String() ?? '',
|
|
||||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
|
||||||
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
|
||||||
createdDate: createdDt?.toIso8601String() ?? '',
|
|
||||||
status: _mapStatus(status),
|
|
||||||
description: app.shift.description,
|
|
||||||
durationDays: app.shift.durationDays,
|
|
||||||
requiredSlots: app.shiftRole.count,
|
|
||||||
filledSlots: app.shiftRole.assigned ?? 0,
|
|
||||||
hasApplied: true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
shifts.add(_mapApplicationToShift(app, _mapStatus(matchingStatus)));
|
||||||
}
|
}
|
||||||
return shifts;
|
return shifts;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -491,7 +466,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
shiftId: shiftId,
|
shiftId: shiftId,
|
||||||
staffId: staffId,
|
staffId: staffId,
|
||||||
roleId: targetRoleId,
|
roleId: targetRoleId,
|
||||||
status: dc.ApplicationStatus.ACCEPTED,
|
status: dc.ApplicationStatus.CONFIRMED,
|
||||||
origin: dc.ApplicationOrigin.STAFF,
|
origin: dc.ApplicationOrigin.STAFF,
|
||||||
)
|
)
|
||||||
// TODO: this should be PENDING so a vendor can accept it.
|
// TODO: this should be PENDING so a vendor can accept it.
|
||||||
|
|||||||
Reference in New Issue
Block a user