Expose parseDouble; fix shift mapping and UI

Rename and expose numeric parser (from _parseDouble to parseDouble) with a doc comment so other modules can reuse it. Update ClockIn repository mapping to populate orderId and prefer clientName for the shift title, and map latitude/longitude using Shift.parseDouble. Remove outdated TODOs and remove the selected/today badge text from the shift card UI. These changes consolidate parsing logic, improve today-shift mapping fidelity, and simplify the shift card display.
This commit is contained in:
Achintha Isuru
2026-03-17 12:14:14 -04:00
parent 376b4e4431
commit d12b45a37d
3 changed files with 8 additions and 22 deletions

View File

@@ -39,8 +39,8 @@ class Shift extends Equatable {
timezone: json['timezone'] as String? ?? 'UTC', timezone: json['timezone'] as String? ?? 'UTC',
locationName: json['locationName'] as String?, locationName: json['locationName'] as String?,
locationAddress: json['locationAddress'] as String?, locationAddress: json['locationAddress'] as String?,
latitude: _parseDouble(json['latitude']), latitude: parseDouble(json['latitude']),
longitude: _parseDouble(json['longitude']), longitude: parseDouble(json['longitude']),
geofenceRadiusMeters: json['geofenceRadiusMeters'] as int?, geofenceRadiusMeters: json['geofenceRadiusMeters'] as int?,
requiredWorkers: json['requiredWorkers'] as int? ?? 1, requiredWorkers: json['requiredWorkers'] as int? ?? 1,
assignedWorkers: json['assignedWorkers'] as int? ?? 0, assignedWorkers: json['assignedWorkers'] as int? ?? 0,
@@ -114,7 +114,8 @@ class Shift extends Equatable {
}; };
} }
static double? _parseDouble(dynamic value) { /// Safely parses a numeric value to double.
static double? parseDouble(dynamic value) {
if (value == null) return null; if (value == null) return null;
if (value is double) return value; if (value is double) return value;
if (value is int) return value.toDouble(); if (value is int) return value.toDouble();

View File

@@ -20,8 +20,6 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
StaffEndpoints.clockInShiftsToday, StaffEndpoints.clockInShiftsToday,
); );
final List<dynamic> items = response.data['items'] as List<dynamic>; final List<dynamic> items = response.data['items'] as List<dynamic>;
// TODO: Ask BE to add latitude, longitude, hourlyRate, and clientName
// to the listTodayShifts query to avoid mapping gaps and extra API calls.
return items return items
.map( .map(
(dynamic json) => (dynamic json) =>
@@ -75,23 +73,17 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
} }
/// Maps a V2 `listTodayShifts` JSON item to the domain [Shift] entity. /// Maps a V2 `listTodayShifts` JSON item to the domain [Shift] entity.
///
/// The today-shifts endpoint returns a lightweight shape that lacks some
/// [Shift] fields. Missing fields are defaulted:
/// - `orderId` defaults to empty string
/// - `latitude` / `longitude` default to null (disables geofence)
/// - `requiredWorkers` / `assignedWorkers` default to 0
// TODO: Ask BE to add latitude/longitude to the listTodayShifts query
// to avoid losing geofence validation.
static Shift _mapTodayShiftJsonToShift(Map<String, dynamic> json) { static Shift _mapTodayShiftJsonToShift(Map<String, dynamic> json) {
return Shift( return Shift(
id: json['shiftId'] as String, id: json['shiftId'] as String,
orderId: '', orderId: json['orderId'] as String? ?? '',
title: json['roleName'] as String? ?? '', title: json['clientName'] as String? ?? json['roleName'] as String? ?? '',
status: ShiftStatus.fromJson(json['attendanceStatus'] as String?), status: ShiftStatus.fromJson(json['attendanceStatus'] as String?),
startsAt: DateTime.parse(json['startTime'] as String), startsAt: DateTime.parse(json['startTime'] as String),
endsAt: DateTime.parse(json['endTime'] as String), endsAt: DateTime.parse(json['endTime'] as String),
locationName: json['location'] as String?, locationName: json['location'] as String?,
latitude: Shift.parseDouble(json['latitude']),
longitude: Shift.parseDouble(json['longitude']),
requiredWorkers: 0, requiredWorkers: 0,
assignedWorkers: 0, assignedWorkers: 0,
); );

View File

@@ -79,13 +79,6 @@ class _ShiftDetails extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text(
isSelected ? i18n.selected_shift_badge : i18n.today_shift_badge,
style: UiTypography.titleUppercase4b.copyWith(
color: isSelected ? UiColors.primary : UiColors.textSecondary,
),
),
const SizedBox(height: 2),
Text(shift.title, style: UiTypography.body2b), Text(shift.title, style: UiTypography.body2b),
// TODO: Ask BE to add clientName to the listTodayShifts response. // TODO: Ask BE to add clientName to the listTodayShifts response.
// Currently showing locationName as subtitle fallback. // Currently showing locationName as subtitle fallback.