refactor: improve code readability and formatting in shifts repository and shift details page

This commit is contained in:
Achintha Isuru
2026-02-01 12:25:45 -05:00
parent 989a1d3f84
commit 5d561ff825
3 changed files with 137 additions and 127 deletions

View File

@@ -37,7 +37,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
} }
try { try {
final response = await _dataConnect.getStaffByUserId(userId: user.uid).execute(); final response = await _dataConnect
.getStaffByUserId(userId: user.uid)
.execute();
if (response.data.staffs.isNotEmpty) { if (response.data.staffs.isNotEmpty) {
_cachedStaffId = response.data.staffs.first.id; _cachedStaffId = response.data.staffs.first.id;
return _cachedStaffId!; return _cachedStaffId!;
@@ -47,9 +49,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
} }
// 4. Fallback (should ideally not happen if DB is seeded) // 4. Fallback (should ideally not happen if DB is seeded)
return user.uid; return user.uid;
} }
DateTime? _toDateTime(dynamic t) { DateTime? _toDateTime(dynamic t) {
if (t == null) return null; if (t == null) return null;
DateTime? dt; DateTime? dt;
@@ -79,7 +81,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
Future<List<Shift>> getMyShifts() async { Future<List<Shift>> getMyShifts() async {
return _fetchApplications(dc.ApplicationStatus.ACCEPTED); return _fetchApplications(dc.ApplicationStatus.ACCEPTED);
} }
@override @override
Future<List<Shift>> getPendingAssignments() async { Future<List<Shift>> getPendingAssignments() async {
return _fetchApplications(dc.ApplicationStatus.PENDING); return _fetchApplications(dc.ApplicationStatus.PENDING);
@@ -102,35 +104,39 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
.getApplicationsByStaffId(staffId: staffId) .getApplicationsByStaffId(staffId: staffId)
.execute(); .execute();
final apps = response.data.applications.where((app) => app.status.stringValue == status.name); final apps = response.data.applications.where(
(app) => app.status.stringValue == status.name,
);
final List<Shift> shifts = []; final List<Shift> shifts = [];
for (final app in apps) { for (final app in apps) {
_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 shift = await _getShiftDetails(app.shift.id); final shift = await _getShiftDetails(app.shift.id);
if (shift != null) { if (shift != null) {
// Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED) // Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED)
shifts.add(Shift( shifts.add(
id: shift.id, Shift(
title: shift.title, id: shift.id,
clientName: shift.clientName, title: shift.title,
logoUrl: shift.logoUrl, clientName: shift.clientName,
hourlyRate: shift.hourlyRate, logoUrl: shift.logoUrl,
location: shift.location, hourlyRate: shift.hourlyRate,
locationAddress: shift.locationAddress, location: shift.location,
date: shift.date, locationAddress: shift.locationAddress,
startTime: shift.startTime, date: shift.date,
endTime: shift.endTime, startTime: shift.startTime,
createdDate: shift.createdDate, endTime: shift.endTime,
status: _mapStatus(status), createdDate: shift.createdDate,
description: shift.description, status: _mapStatus(status),
durationDays: shift.durationDays, description: shift.description,
requiredSlots: shift.requiredSlots, durationDays: shift.durationDays,
filledSlots: shift.filledSlots, requiredSlots: shift.requiredSlots,
)); filledSlots: shift.filledSlots,
} ),
);
}
} }
return shifts; return shifts;
} catch (e) { } catch (e) {
@@ -157,8 +163,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
@override @override
Future<List<Shift>> getAvailableShifts(String query, String type) async { Future<List<Shift>> getAvailableShifts(String query, String type) async {
try { try {
final String? vendorId = final String? vendorId = dc.StaffSessionStore.instance.session?.ownerId;
dc.StaffSessionStore.instance.session?.ownerId;
if (vendorId == null || vendorId.isEmpty) { if (vendorId == null || vendorId.isEmpty) {
return <Shift>[]; return <Shift>[];
} }
@@ -184,8 +189,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
location: sr.shift.location ?? '', location: sr.shift.location ?? '',
locationAddress: sr.shift.locationAddress ?? '', locationAddress: sr.shift.locationAddress ?? '',
date: startDt?.toIso8601String() ?? '', date: startDt?.toIso8601String() ?? '',
startTime: startTime: startDt != null
startDt != null ? DateFormat('HH:mm').format(startDt) : '', ? DateFormat('HH:mm').format(startDt)
: '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '', endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '', createdDate: createdDt?.toIso8601String() ?? '',
status: sr.shift.status?.stringValue.toLowerCase() ?? 'open', status: sr.shift.status?.stringValue.toLowerCase() ?? 'open',
@@ -217,7 +223,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
Future<Shift?> getShiftDetails(String shiftId, {String? roleId}) async { Future<Shift?> getShiftDetails(String shiftId, {String? roleId}) async {
return _getShiftDetails(shiftId, roleId: roleId); return _getShiftDetails(shiftId, roleId: roleId);
} }
Future<Shift?> _getShiftDetails(String shiftId, {String? roleId}) async { Future<Shift?> _getShiftDetails(String shiftId, {String? roleId}) async {
try { try {
if (roleId != null && roleId.isNotEmpty) { if (roleId != null && roleId.isNotEmpty) {
@@ -235,12 +241,12 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
bool hasApplied = false; bool hasApplied = false;
String status = 'open'; String status = 'open';
if (staffId != null) { if (staffId != null) {
final apps = final apps = await _dataConnect
await _dataConnect.getApplicationsByStaffId(staffId: staffId).execute(); .getApplicationsByStaffId(staffId: staffId)
.execute();
final app = apps.data.applications final app = apps.data.applications
.where( .where(
(a) => (a) => a.shiftId == shiftId && a.shiftRole.roleId == roleId,
a.shiftId == shiftId && a.shiftRole.roleId == roleId,
) )
.firstOrNull; .firstOrNull;
if (app != null) { if (app != null) {
@@ -260,8 +266,8 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
clientName: sr.shift.order.business.businessName, clientName: sr.shift.order.business.businessName,
logoUrl: sr.shift.order.business.companyLogoUrl, logoUrl: sr.shift.order.business.companyLogoUrl,
hourlyRate: sr.role.costPerHour, hourlyRate: sr.role.costPerHour,
location: sr.shift.order.teamHub.hubName, location: sr.shift.location ?? sr.shift.order.teamHub.hubName,
locationAddress: '', locationAddress: sr.shift.locationAddress ?? '',
date: startDt?.toIso8601String() ?? '', date: startDt?.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) : '', endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
@@ -279,19 +285,21 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
final result = await _dataConnect.getShiftById(id: shiftId).execute(); final result = await _dataConnect.getShiftById(id: shiftId).execute();
final s = result.data.shift; final s = result.data.shift;
if (s == null) return null; if (s == null) return null;
int? required; int? required;
int? filled; int? filled;
try { try {
final rolesRes = await _dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute(); final rolesRes = await _dataConnect
if (rolesRes.data.shiftRoles.isNotEmpty) { .listShiftRolesByShiftId(shiftId: shiftId)
required = 0; .execute();
filled = 0; if (rolesRes.data.shiftRoles.isNotEmpty) {
for(var r in rolesRes.data.shiftRoles) { required = 0;
required = (required ?? 0) + r.count; filled = 0;
filled = (filled ?? 0) + (r.assigned ?? 0); for (var r in rolesRes.data.shiftRoles) {
} required = (required ?? 0) + r.count;
filled = (filled ?? 0) + (r.assigned ?? 0);
} }
}
} catch (_) {} } catch (_) {}
final startDt = _toDateTime(s.startTime); final startDt = _toDateTime(s.startTime);
@@ -299,22 +307,22 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
final createdDt = _toDateTime(s.createdAt); final createdDt = _toDateTime(s.createdAt);
return Shift( return Shift(
id: s.id, id: s.id,
title: s.title, title: s.title,
clientName: s.order.business.businessName, clientName: s.order.business.businessName,
logoUrl: null, logoUrl: null,
hourlyRate: s.cost ?? 0.0, hourlyRate: s.cost ?? 0.0,
location: s.location ?? '', location: s.location ?? '',
locationAddress: s.locationAddress ?? '', locationAddress: s.locationAddress ?? '',
date: startDt?.toIso8601String() ?? '', date: startDt?.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) : '', endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '', createdDate: createdDt?.toIso8601String() ?? '',
status: s.status?.stringValue ?? 'OPEN', status: s.status?.stringValue ?? 'OPEN',
description: s.description, description: s.description,
durationDays: s.durationDays, durationDays: s.durationDays,
requiredSlots: required, requiredSlots: required,
filledSlots: filled, filledSlots: filled,
); );
} catch (e) { } catch (e) {
return null; return null;
@@ -331,8 +339,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
String targetRoleId = roleId ?? ''; String targetRoleId = roleId ?? '';
if (targetRoleId.isEmpty) { if (targetRoleId.isEmpty) {
final rolesResult = final rolesResult = await _dataConnect
await _dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute(); .listShiftRolesByShiftId(shiftId: shiftId)
.execute();
if (rolesResult.data.shiftRoles.isEmpty) { if (rolesResult.data.shiftRoles.isEmpty) {
throw Exception('No open roles for this shift'); throw Exception('No open roles for this shift');
} }
@@ -384,10 +393,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
.execute(); .execute();
updatedRole = true; updatedRole = true;
await _dataConnect await _dataConnect.updateShift(id: shiftId).filled(filled + 1).execute();
.updateShift(id: shiftId)
.filled(filled + 1)
.execute();
updatedShift = true; updatedShift = true;
} catch (e) { } catch (e) {
if (updatedShift) { if (updatedShift) {
@@ -408,15 +414,18 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
@override @override
Future<void> acceptShift(String shiftId) async { Future<void> acceptShift(String shiftId) async {
await _updateApplicationStatus(shiftId, dc.ApplicationStatus.ACCEPTED); await _updateApplicationStatus(shiftId, dc.ApplicationStatus.ACCEPTED);
}
@override
Future<void> declineShift(String shiftId) async {
await _updateApplicationStatus(shiftId, dc.ApplicationStatus.REJECTED);
} }
Future<void> _updateApplicationStatus(String shiftId, dc.ApplicationStatus newStatus) async { @override
Future<void> declineShift(String shiftId) async {
await _updateApplicationStatus(shiftId, dc.ApplicationStatus.REJECTED);
}
Future<void> _updateApplicationStatus(
String shiftId,
dc.ApplicationStatus newStatus,
) async {
String? appId = _shiftToAppIdMap[shiftId]; String? appId = _shiftToAppIdMap[shiftId];
String? roleId; String? roleId;
@@ -427,43 +436,49 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
// Re-check map // Re-check map
appId = _shiftToAppIdMap[shiftId]; appId = _shiftToAppIdMap[shiftId];
if (appId != null) { if (appId != null) {
roleId = _appToRoleIdMap[appId]; roleId = _appToRoleIdMap[appId];
} else { } else {
// Fallback fetch // Fallback fetch
final staffId = await _getStaffId(); final staffId = await _getStaffId();
final apps = await _dataConnect.getApplicationsByStaffId(staffId: staffId).execute(); final apps = await _dataConnect
final app = apps.data.applications.where((a) => a.shiftId == shiftId).firstOrNull; .getApplicationsByStaffId(staffId: staffId)
if (app != null) { .execute();
appId = app.id; final app = apps.data.applications
roleId = app.shiftRole.id; .where((a) => a.shiftId == shiftId)
} .firstOrNull;
if (app != null) {
appId = app.id;
roleId = app.shiftRole.id;
}
} }
if (appId == null || roleId == null) { if (appId == null || roleId == null) {
// If we are rejecting and can't find an application, create one as rejected (declining an available shift) // If we are rejecting and can't find an application, create one as rejected (declining an available shift)
if (newStatus == dc.ApplicationStatus.REJECTED) { if (newStatus == dc.ApplicationStatus.REJECTED) {
final rolesResult = await _dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute(); final rolesResult = await _dataConnect
if (rolesResult.data.shiftRoles.isNotEmpty) { .listShiftRolesByShiftId(shiftId: shiftId)
final role = rolesResult.data.shiftRoles.first; .execute();
final staffId = await _getStaffId(); if (rolesResult.data.shiftRoles.isNotEmpty) {
await _dataConnect.createApplication( final role = rolesResult.data.shiftRoles.first;
final staffId = await _getStaffId();
await _dataConnect
.createApplication(
shiftId: shiftId, shiftId: shiftId,
staffId: staffId, staffId: staffId,
roleId: role.id, roleId: role.id,
status: dc.ApplicationStatus.REJECTED, status: dc.ApplicationStatus.REJECTED,
origin: dc.ApplicationOrigin.STAFF, origin: dc.ApplicationOrigin.STAFF,
).execute(); )
return; .execute();
} return;
}
} }
throw Exception("Application not found for shift $shiftId"); throw Exception("Application not found for shift $shiftId");
} }
await _dataConnect.updateApplicationStatus( await _dataConnect
id: appId, .updateApplicationStatus(id: appId, roleId: roleId)
roleId: roleId, .status(newStatus)
) .execute();
.status(newStatus)
.execute();
} }
} }

View File

@@ -123,12 +123,8 @@ class ShiftDetailsPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider<ShiftDetailsBloc>( return BlocProvider<ShiftDetailsBloc>(
create: (_) => create: (_) =>
Modular.get<ShiftDetailsBloc>()..add( Modular.get<ShiftDetailsBloc>()
LoadShiftDetailsEvent( ..add(LoadShiftDetailsEvent(shiftId, roleId: shift?.roleId)),
shiftId,
roleId: shift?.roleId,
),
),
child: BlocListener<ShiftDetailsBloc, ShiftDetailsState>( child: BlocListener<ShiftDetailsBloc, ShiftDetailsState>(
listener: (context, state) { listener: (context, state) {
if (state is ShiftActionSuccess) { if (state is ShiftActionSuccess) {
@@ -140,12 +136,14 @@ class ShiftDetailsPage extends StatelessWidget {
); );
Modular.to.navigateToShiftsHome(); Modular.to.navigateToShiftsHome();
} else if (state is ShiftDetailsError) { } else if (state is ShiftDetailsError) {
ScaffoldMessenger.of(context).showSnackBar( if (shift == null) {
SnackBar( ScaffoldMessenger.of(context).showSnackBar(
content: Text(state.message), SnackBar(
backgroundColor: const Color(0xFFEF4444), content: Text(state.message),
), backgroundColor: const Color(0xFFEF4444),
); ),
);
}
} }
}, },
child: BlocBuilder<ShiftDetailsBloc, ShiftDetailsState>( child: BlocBuilder<ShiftDetailsBloc, ShiftDetailsState>(
@@ -180,7 +178,7 @@ class ShiftDetailsPage extends StatelessWidget {
appBar: UiAppBar( appBar: UiAppBar(
title: displayShift.title, title: displayShift.title,
centerTitle: false, centerTitle: false,
onLeadingPressed:() => Modular.to.navigateToShiftsHome(), onLeadingPressed: () => Modular.to.navigateToShiftsHome(),
), ),
body: Column( body: Column(
children: [ children: [
@@ -403,14 +401,14 @@ class ShiftDetailsPage extends StatelessWidget {
color: UiColors.textPrimary, color: UiColors.textPrimary,
), ),
), ),
Text( Text(
displayShift.location.isEmpty displayShift.location.isEmpty
? "TBD" ? "TBD"
: displayShift.locationAddress, : displayShift.locationAddress,
style: UiTypography.title1m.copyWith( style: UiTypography.title1m.copyWith(
color: UiColors.textPrimary, color: UiColors.textPrimary,
), ),
), ),
], ],
), ),
], ],

View File

@@ -135,10 +135,7 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
final visibleMyShifts = widget.myShifts.where((s) { final visibleMyShifts = widget.myShifts.where((s) {
try { try {
final date = DateTime.parse(s.date); final date = DateTime.parse(s.date);
return date.isAfter( return _isSameDay(date, _selectedDate);
weekStartDate.subtract(const Duration(seconds: 1)),
) &&
date.isBefore(weekEndDate.add(const Duration(days: 1)));
} catch (_) { } catch (_) {
return false; return false;
} }