feat: Add orderId and normalized orderType to the Shift model to enable UI grouping and type-badging in shift displays.
This commit is contained in:
@@ -10,9 +10,8 @@ import '../../domain/repositories/shifts_connector_repository.dart';
|
||||
/// Handles shift-related data operations by interacting with Data Connect.
|
||||
class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
/// Creates a new [ShiftsConnectorRepositoryImpl].
|
||||
ShiftsConnectorRepositoryImpl({
|
||||
dc.DataConnectService? service,
|
||||
}) : _service = service ?? dc.DataConnectService.instance;
|
||||
ShiftsConnectorRepositoryImpl({dc.DataConnectService? service})
|
||||
: _service = service ?? dc.DataConnectService.instance;
|
||||
|
||||
final dc.DataConnectService _service;
|
||||
|
||||
@@ -23,12 +22,17 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
required DateTime end,
|
||||
}) async {
|
||||
return _service.run(() async {
|
||||
final dc.GetApplicationsByStaffIdVariablesBuilder query = _service.connector
|
||||
final dc.GetApplicationsByStaffIdVariablesBuilder query = _service
|
||||
.connector
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.dayStart(_service.toTimestamp(start))
|
||||
.dayEnd(_service.toTimestamp(end));
|
||||
|
||||
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> response = await query.execute();
|
||||
final QueryResult<
|
||||
dc.GetApplicationsByStaffIdData,
|
||||
dc.GetApplicationsByStaffIdVariables
|
||||
>
|
||||
response = await query.execute();
|
||||
return _mapApplicationsToShifts(response.data.applications);
|
||||
});
|
||||
}
|
||||
@@ -45,18 +49,28 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
final String? vendorId = dc.StaffSessionStore.instance.session?.ownerId;
|
||||
if (vendorId == null || vendorId.isEmpty) return <Shift>[];
|
||||
|
||||
final QueryResult<dc.ListShiftRolesByVendorIdData, dc.ListShiftRolesByVendorIdVariables> response = await _service.connector
|
||||
final QueryResult<
|
||||
dc.ListShiftRolesByVendorIdData,
|
||||
dc.ListShiftRolesByVendorIdVariables
|
||||
>
|
||||
response = await _service.connector
|
||||
.listShiftRolesByVendorId(vendorId: vendorId)
|
||||
.execute();
|
||||
|
||||
final List<dc.ListShiftRolesByVendorIdShiftRoles> allShiftRoles = response.data.shiftRoles;
|
||||
final List<dc.ListShiftRolesByVendorIdShiftRoles> allShiftRoles =
|
||||
response.data.shiftRoles;
|
||||
|
||||
// Fetch current applications to filter out already booked shifts
|
||||
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> myAppsResponse = await _service.connector
|
||||
final QueryResult<
|
||||
dc.GetApplicationsByStaffIdData,
|
||||
dc.GetApplicationsByStaffIdVariables
|
||||
>
|
||||
myAppsResponse = await _service.connector
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
final Set<String> appliedShiftIds =
|
||||
myAppsResponse.data.applications.map((dc.GetApplicationsByStaffIdApplications a) => a.shiftId).toSet();
|
||||
final Set<String> appliedShiftIds = myAppsResponse.data.applications
|
||||
.map((dc.GetApplicationsByStaffIdApplications a) => a.shiftId)
|
||||
.toSet();
|
||||
|
||||
final List<Shift> mappedShifts = <Shift>[];
|
||||
for (final dc.ListShiftRolesByVendorIdShiftRoles sr in allShiftRoles) {
|
||||
@@ -67,6 +81,12 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
final DateTime? endDt = _service.toDateTime(sr.endTime);
|
||||
final DateTime? createdDt = _service.toDateTime(sr.createdAt);
|
||||
|
||||
// Normalise orderType to uppercase for consistent checks in the UI.
|
||||
// RECURRING → groups shifts into Multi-Day cards.
|
||||
// PERMANENT → groups shifts into Long Term cards.
|
||||
final String orderTypeStr = sr.shift.order.orderType.stringValue
|
||||
.toUpperCase();
|
||||
|
||||
mappedShifts.add(
|
||||
Shift(
|
||||
id: sr.shiftId,
|
||||
@@ -78,7 +98,9 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
location: sr.shift.location ?? '',
|
||||
locationAddress: sr.shift.locationAddress ?? '',
|
||||
date: shiftDate?.toIso8601String() ?? '',
|
||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
||||
startTime: startDt != null
|
||||
? DateFormat('HH:mm').format(startDt)
|
||||
: '',
|
||||
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
||||
createdDate: createdDt?.toIso8601String() ?? '',
|
||||
status: sr.shift.status?.stringValue.toLowerCase() ?? 'open',
|
||||
@@ -88,6 +110,10 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
filledSlots: sr.assigned ?? 0,
|
||||
latitude: sr.shift.latitude,
|
||||
longitude: sr.shift.longitude,
|
||||
// orderId + orderType power the grouping and type-badge logic in
|
||||
// FindShiftsTab._groupMultiDayShifts and MyShiftCard._getShiftType.
|
||||
orderId: sr.shift.orderId,
|
||||
orderType: orderTypeStr,
|
||||
breakInfo: BreakAdapter.fromData(
|
||||
isPaid: sr.isBreakPaid ?? false,
|
||||
breakTime: sr.breakType?.stringValue,
|
||||
@@ -125,7 +151,8 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
}) async {
|
||||
return _service.run(() async {
|
||||
if (roleId != null && roleId.isNotEmpty) {
|
||||
final QueryResult<dc.GetShiftRoleByIdData, dc.GetShiftRoleByIdVariables> roleResult = await _service.connector
|
||||
final QueryResult<dc.GetShiftRoleByIdData, dc.GetShiftRoleByIdVariables>
|
||||
roleResult = await _service.connector
|
||||
.getShiftRoleById(shiftId: shiftId, roleId: roleId)
|
||||
.execute();
|
||||
final dc.GetShiftRoleByIdShiftRole? sr = roleResult.data.shiftRole;
|
||||
@@ -137,13 +164,22 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
|
||||
bool hasApplied = false;
|
||||
String status = 'open';
|
||||
|
||||
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> appsResponse = await _service.connector
|
||||
|
||||
final QueryResult<
|
||||
dc.GetApplicationsByStaffIdData,
|
||||
dc.GetApplicationsByStaffIdVariables
|
||||
>
|
||||
appsResponse = await _service.connector
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
|
||||
final dc.GetApplicationsByStaffIdApplications? app = appsResponse.data.applications
|
||||
.where((dc.GetApplicationsByStaffIdApplications a) => a.shiftId == shiftId && a.shiftRole.roleId == roleId)
|
||||
|
||||
final dc.GetApplicationsByStaffIdApplications? app = appsResponse
|
||||
.data
|
||||
.applications
|
||||
.where(
|
||||
(dc.GetApplicationsByStaffIdApplications a) =>
|
||||
a.shiftId == shiftId && a.shiftRole.roleId == roleId,
|
||||
)
|
||||
.firstOrNull;
|
||||
|
||||
if (app != null) {
|
||||
@@ -181,7 +217,8 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
);
|
||||
}
|
||||
|
||||
final QueryResult<dc.GetShiftByIdData, dc.GetShiftByIdVariables> result = await _service.connector.getShiftById(id: shiftId).execute();
|
||||
final QueryResult<dc.GetShiftByIdData, dc.GetShiftByIdVariables> result =
|
||||
await _service.connector.getShiftById(id: shiftId).execute();
|
||||
final dc.GetShiftByIdShift? s = result.data.shift;
|
||||
if (s == null) return null;
|
||||
|
||||
@@ -190,17 +227,23 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
Break? breakInfo;
|
||||
|
||||
try {
|
||||
final QueryResult<dc.ListShiftRolesByShiftIdData, dc.ListShiftRolesByShiftIdVariables> rolesRes = await _service.connector
|
||||
final QueryResult<
|
||||
dc.ListShiftRolesByShiftIdData,
|
||||
dc.ListShiftRolesByShiftIdVariables
|
||||
>
|
||||
rolesRes = await _service.connector
|
||||
.listShiftRolesByShiftId(shiftId: shiftId)
|
||||
.execute();
|
||||
if (rolesRes.data.shiftRoles.isNotEmpty) {
|
||||
required = 0;
|
||||
filled = 0;
|
||||
for (dc.ListShiftRolesByShiftIdShiftRoles r in rolesRes.data.shiftRoles) {
|
||||
for (dc.ListShiftRolesByShiftIdShiftRoles r
|
||||
in rolesRes.data.shiftRoles) {
|
||||
required = (required ?? 0) + r.count;
|
||||
filled = (filled ?? 0) + (r.assigned ?? 0);
|
||||
}
|
||||
final dc.ListShiftRolesByShiftIdShiftRoles firstRole = rolesRes.data.shiftRoles.first;
|
||||
final dc.ListShiftRolesByShiftIdShiftRoles firstRole =
|
||||
rolesRes.data.shiftRoles.first;
|
||||
breakInfo = BreakAdapter.fromData(
|
||||
isPaid: firstRole.isBreakPaid ?? false,
|
||||
breakTime: firstRole.breakType?.stringValue,
|
||||
@@ -247,35 +290,53 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
final String targetRoleId = roleId ?? '';
|
||||
if (targetRoleId.isEmpty) throw Exception('Missing role id.');
|
||||
|
||||
final QueryResult<dc.GetShiftRoleByIdData, dc.GetShiftRoleByIdVariables> roleResult = await _service.connector
|
||||
final QueryResult<dc.GetShiftRoleByIdData, dc.GetShiftRoleByIdVariables>
|
||||
roleResult = await _service.connector
|
||||
.getShiftRoleById(shiftId: shiftId, roleId: targetRoleId)
|
||||
.execute();
|
||||
final dc.GetShiftRoleByIdShiftRole? role = roleResult.data.shiftRole;
|
||||
if (role == null) throw Exception('Shift role not found');
|
||||
|
||||
final QueryResult<dc.GetShiftByIdData, dc.GetShiftByIdVariables> shiftResult = await _service.connector.getShiftById(id: shiftId).execute();
|
||||
final QueryResult<dc.GetShiftByIdData, dc.GetShiftByIdVariables>
|
||||
shiftResult = await _service.connector
|
||||
.getShiftById(id: shiftId)
|
||||
.execute();
|
||||
final dc.GetShiftByIdShift? shift = shiftResult.data.shift;
|
||||
if (shift == null) throw Exception('Shift not found');
|
||||
|
||||
// Validate daily limit
|
||||
final DateTime? shiftDate = _service.toDateTime(shift.date);
|
||||
if (shiftDate != null) {
|
||||
final DateTime dayStartUtc = DateTime.utc(shiftDate.year, shiftDate.month, shiftDate.day);
|
||||
final DateTime dayEndUtc = dayStartUtc.add(const Duration(days: 1)).subtract(const Duration(microseconds: 1));
|
||||
final DateTime dayStartUtc = DateTime.utc(
|
||||
shiftDate.year,
|
||||
shiftDate.month,
|
||||
shiftDate.day,
|
||||
);
|
||||
final DateTime dayEndUtc = dayStartUtc
|
||||
.add(const Duration(days: 1))
|
||||
.subtract(const Duration(microseconds: 1));
|
||||
|
||||
final QueryResult<dc.VaidateDayStaffApplicationData, dc.VaidateDayStaffApplicationVariables> validationResponse = await _service.connector
|
||||
final QueryResult<
|
||||
dc.VaidateDayStaffApplicationData,
|
||||
dc.VaidateDayStaffApplicationVariables
|
||||
>
|
||||
validationResponse = await _service.connector
|
||||
.vaidateDayStaffApplication(staffId: staffId)
|
||||
.dayStart(_service.toTimestamp(dayStartUtc))
|
||||
.dayEnd(_service.toTimestamp(dayEndUtc))
|
||||
.execute();
|
||||
|
||||
|
||||
if (validationResponse.data.applications.isNotEmpty) {
|
||||
throw Exception('The user already has a shift that day.');
|
||||
}
|
||||
}
|
||||
|
||||
// Check for existing application
|
||||
final QueryResult<dc.GetApplicationByStaffShiftAndRoleData, dc.GetApplicationByStaffShiftAndRoleVariables> existingAppRes = await _service.connector
|
||||
final QueryResult<
|
||||
dc.GetApplicationByStaffShiftAndRoleData,
|
||||
dc.GetApplicationByStaffShiftAndRoleVariables
|
||||
>
|
||||
existingAppRes = await _service.connector
|
||||
.getApplicationByStaffShiftAndRole(
|
||||
staffId: staffId,
|
||||
shiftId: shiftId,
|
||||
@@ -295,14 +356,20 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
|
||||
String? createdAppId;
|
||||
try {
|
||||
final OperationResult<dc.CreateApplicationData, dc.CreateApplicationVariables> createRes = await _service.connector.createApplication(
|
||||
shiftId: shiftId,
|
||||
staffId: staffId,
|
||||
roleId: targetRoleId,
|
||||
status: dc.ApplicationStatus.CONFIRMED, // Matches existing logic
|
||||
origin: dc.ApplicationOrigin.STAFF,
|
||||
).execute();
|
||||
|
||||
final OperationResult<
|
||||
dc.CreateApplicationData,
|
||||
dc.CreateApplicationVariables
|
||||
>
|
||||
createRes = await _service.connector
|
||||
.createApplication(
|
||||
shiftId: shiftId,
|
||||
staffId: staffId,
|
||||
roleId: targetRoleId,
|
||||
status: dc.ApplicationStatus.CONFIRMED, // Matches existing logic
|
||||
origin: dc.ApplicationOrigin.STAFF,
|
||||
)
|
||||
.execute();
|
||||
|
||||
createdAppId = createRes.data.application_insert.id;
|
||||
|
||||
await _service.connector
|
||||
@@ -317,7 +384,9 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
} catch (e) {
|
||||
// Simple rollback attempt (not guaranteed)
|
||||
if (createdAppId != null) {
|
||||
await _service.connector.deleteApplication(id: createdAppId).execute();
|
||||
await _service.connector
|
||||
.deleteApplication(id: createdAppId)
|
||||
.execute();
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
@@ -325,11 +394,12 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> acceptShift({
|
||||
required String shiftId,
|
||||
required String staffId,
|
||||
}) {
|
||||
return _updateApplicationStatus(shiftId, staffId, dc.ApplicationStatus.CONFIRMED);
|
||||
Future<void> acceptShift({required String shiftId, required String staffId}) {
|
||||
return _updateApplicationStatus(
|
||||
shiftId,
|
||||
staffId,
|
||||
dc.ApplicationStatus.CONFIRMED,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -337,7 +407,11 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
required String shiftId,
|
||||
required String staffId,
|
||||
}) {
|
||||
return _updateApplicationStatus(shiftId, staffId, dc.ApplicationStatus.REJECTED);
|
||||
return _updateApplicationStatus(
|
||||
shiftId,
|
||||
staffId,
|
||||
dc.ApplicationStatus.REJECTED,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -351,18 +425,24 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
@override
|
||||
Future<List<Shift>> getHistoryShifts({required String staffId}) async {
|
||||
return _service.run(() async {
|
||||
final QueryResult<dc.ListCompletedApplicationsByStaffIdData, dc.ListCompletedApplicationsByStaffIdVariables> response = await _service.connector
|
||||
final QueryResult<
|
||||
dc.ListCompletedApplicationsByStaffIdData,
|
||||
dc.ListCompletedApplicationsByStaffIdVariables
|
||||
>
|
||||
response = await _service.connector
|
||||
.listCompletedApplicationsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
|
||||
|
||||
final List<Shift> shifts = <Shift>[];
|
||||
for (final dc.ListCompletedApplicationsByStaffIdApplications app in response.data.applications) {
|
||||
for (final dc.ListCompletedApplicationsByStaffIdApplications app
|
||||
in response.data.applications) {
|
||||
final String roleName = app.shiftRole.role.name;
|
||||
final String orderName = (app.shift.order.eventName ?? '').trim().isNotEmpty
|
||||
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 = _service.toDateTime(app.shift.date);
|
||||
final DateTime? startDt = _service.toDateTime(app.shiftRole.startTime);
|
||||
final DateTime? endDt = _service.toDateTime(app.shiftRole.endTime);
|
||||
@@ -379,7 +459,9 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
location: app.shift.location ?? '',
|
||||
locationAddress: app.shift.order.teamHub.hubName,
|
||||
date: shiftDate?.toIso8601String() ?? '',
|
||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
||||
startTime: startDt != null
|
||||
? DateFormat('HH:mm').format(startDt)
|
||||
: '',
|
||||
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
||||
createdDate: createdDt?.toIso8601String() ?? '',
|
||||
status: 'completed', // Hardcoded as checked out implies completion
|
||||
@@ -406,7 +488,8 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
List<Shift> _mapApplicationsToShifts(List<dynamic> apps) {
|
||||
return apps.map((app) {
|
||||
final String roleName = app.shiftRole.role.name;
|
||||
final String orderName = (app.shift.order.eventName ?? '').trim().isNotEmpty
|
||||
final String orderName =
|
||||
(app.shift.order.eventName ?? '').trim().isNotEmpty
|
||||
? app.shift.order.eventName!
|
||||
: app.shift.order.business.businessName;
|
||||
final String title = '$roleName - $orderName';
|
||||
@@ -418,7 +501,7 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
|
||||
final bool hasCheckIn = app.checkInTime != null;
|
||||
final bool hasCheckOut = app.checkOutTime != null;
|
||||
|
||||
|
||||
String status;
|
||||
if (hasCheckOut) {
|
||||
status = 'completed';
|
||||
@@ -479,12 +562,20 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
) async {
|
||||
return _service.run(() async {
|
||||
// First try to find the application
|
||||
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> appsResponse = await _service.connector
|
||||
final QueryResult<
|
||||
dc.GetApplicationsByStaffIdData,
|
||||
dc.GetApplicationsByStaffIdVariables
|
||||
>
|
||||
appsResponse = await _service.connector
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
|
||||
final dc.GetApplicationsByStaffIdApplications? app = appsResponse.data.applications
|
||||
.where((dc.GetApplicationsByStaffIdApplications a) => a.shiftId == shiftId)
|
||||
|
||||
final dc.GetApplicationsByStaffIdApplications? app = appsResponse
|
||||
.data
|
||||
.applications
|
||||
.where(
|
||||
(dc.GetApplicationsByStaffIdApplications a) => a.shiftId == shiftId,
|
||||
)
|
||||
.firstOrNull;
|
||||
|
||||
if (app != null) {
|
||||
@@ -494,19 +585,26 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
.execute();
|
||||
} else if (newStatus == dc.ApplicationStatus.REJECTED) {
|
||||
// If declining but no app found, create a rejected application
|
||||
final QueryResult<dc.ListShiftRolesByShiftIdData, dc.ListShiftRolesByShiftIdVariables> rolesRes = await _service.connector
|
||||
final QueryResult<
|
||||
dc.ListShiftRolesByShiftIdData,
|
||||
dc.ListShiftRolesByShiftIdVariables
|
||||
>
|
||||
rolesRes = await _service.connector
|
||||
.listShiftRolesByShiftId(shiftId: shiftId)
|
||||
.execute();
|
||||
|
||||
|
||||
if (rolesRes.data.shiftRoles.isNotEmpty) {
|
||||
final dc.ListShiftRolesByShiftIdShiftRoles firstRole = rolesRes.data.shiftRoles.first;
|
||||
await _service.connector.createApplication(
|
||||
shiftId: shiftId,
|
||||
staffId: staffId,
|
||||
roleId: firstRole.id,
|
||||
status: dc.ApplicationStatus.REJECTED,
|
||||
origin: dc.ApplicationOrigin.STAFF,
|
||||
).execute();
|
||||
final dc.ListShiftRolesByShiftIdShiftRoles firstRole =
|
||||
rolesRes.data.shiftRoles.first;
|
||||
await _service.connector
|
||||
.createApplication(
|
||||
shiftId: shiftId,
|
||||
staffId: staffId,
|
||||
roleId: firstRole.id,
|
||||
status: dc.ApplicationStatus.REJECTED,
|
||||
origin: dc.ApplicationOrigin.STAFF,
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
} else {
|
||||
throw Exception("Application not found for shift $shiftId");
|
||||
@@ -514,4 +612,3 @@ class ShiftsConnectorRepositoryImpl implements ShiftsConnectorRepository {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user