refactor: improve code readability and formatting in shifts repository and shift details page
This commit is contained in:
@@ -37,7 +37,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await _dataConnect.getStaffByUserId(userId: user.uid).execute();
|
||||
final response = await _dataConnect
|
||||
.getStaffByUserId(userId: user.uid)
|
||||
.execute();
|
||||
if (response.data.staffs.isNotEmpty) {
|
||||
_cachedStaffId = response.data.staffs.first.id;
|
||||
return _cachedStaffId!;
|
||||
@@ -47,9 +49,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
}
|
||||
|
||||
// 4. Fallback (should ideally not happen if DB is seeded)
|
||||
return user.uid;
|
||||
return user.uid;
|
||||
}
|
||||
|
||||
|
||||
DateTime? _toDateTime(dynamic t) {
|
||||
if (t == null) return null;
|
||||
DateTime? dt;
|
||||
@@ -79,7 +81,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
Future<List<Shift>> getMyShifts() async {
|
||||
return _fetchApplications(dc.ApplicationStatus.ACCEPTED);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future<List<Shift>> getPendingAssignments() async {
|
||||
return _fetchApplications(dc.ApplicationStatus.PENDING);
|
||||
@@ -102,35 +104,39 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.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 = [];
|
||||
|
||||
for (final app in apps) {
|
||||
_shiftToAppIdMap[app.shift.id] = app.id;
|
||||
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
||||
|
||||
final shift = await _getShiftDetails(app.shift.id);
|
||||
if (shift != null) {
|
||||
// Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED)
|
||||
shifts.add(Shift(
|
||||
id: shift.id,
|
||||
title: shift.title,
|
||||
clientName: shift.clientName,
|
||||
logoUrl: shift.logoUrl,
|
||||
hourlyRate: shift.hourlyRate,
|
||||
location: shift.location,
|
||||
locationAddress: shift.locationAddress,
|
||||
date: shift.date,
|
||||
startTime: shift.startTime,
|
||||
endTime: shift.endTime,
|
||||
createdDate: shift.createdDate,
|
||||
status: _mapStatus(status),
|
||||
description: shift.description,
|
||||
durationDays: shift.durationDays,
|
||||
requiredSlots: shift.requiredSlots,
|
||||
filledSlots: shift.filledSlots,
|
||||
));
|
||||
}
|
||||
_shiftToAppIdMap[app.shift.id] = app.id;
|
||||
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
||||
|
||||
final shift = await _getShiftDetails(app.shift.id);
|
||||
if (shift != null) {
|
||||
// Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED)
|
||||
shifts.add(
|
||||
Shift(
|
||||
id: shift.id,
|
||||
title: shift.title,
|
||||
clientName: shift.clientName,
|
||||
logoUrl: shift.logoUrl,
|
||||
hourlyRate: shift.hourlyRate,
|
||||
location: shift.location,
|
||||
locationAddress: shift.locationAddress,
|
||||
date: shift.date,
|
||||
startTime: shift.startTime,
|
||||
endTime: shift.endTime,
|
||||
createdDate: shift.createdDate,
|
||||
status: _mapStatus(status),
|
||||
description: shift.description,
|
||||
durationDays: shift.durationDays,
|
||||
requiredSlots: shift.requiredSlots,
|
||||
filledSlots: shift.filledSlots,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return shifts;
|
||||
} catch (e) {
|
||||
@@ -157,8 +163,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
@override
|
||||
Future<List<Shift>> getAvailableShifts(String query, String type) async {
|
||||
try {
|
||||
final String? vendorId =
|
||||
dc.StaffSessionStore.instance.session?.ownerId;
|
||||
final String? vendorId = dc.StaffSessionStore.instance.session?.ownerId;
|
||||
if (vendorId == null || vendorId.isEmpty) {
|
||||
return <Shift>[];
|
||||
}
|
||||
@@ -184,8 +189,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
location: sr.shift.location ?? '',
|
||||
locationAddress: sr.shift.locationAddress ?? '',
|
||||
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) : '',
|
||||
createdDate: createdDt?.toIso8601String() ?? '',
|
||||
status: sr.shift.status?.stringValue.toLowerCase() ?? 'open',
|
||||
@@ -217,7 +223,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
Future<Shift?> getShiftDetails(String shiftId, {String? roleId}) async {
|
||||
return _getShiftDetails(shiftId, roleId: roleId);
|
||||
}
|
||||
|
||||
|
||||
Future<Shift?> _getShiftDetails(String shiftId, {String? roleId}) async {
|
||||
try {
|
||||
if (roleId != null && roleId.isNotEmpty) {
|
||||
@@ -235,12 +241,12 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
bool hasApplied = false;
|
||||
String status = 'open';
|
||||
if (staffId != null) {
|
||||
final apps =
|
||||
await _dataConnect.getApplicationsByStaffId(staffId: staffId).execute();
|
||||
final apps = await _dataConnect
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
final app = apps.data.applications
|
||||
.where(
|
||||
(a) =>
|
||||
a.shiftId == shiftId && a.shiftRole.roleId == roleId,
|
||||
(a) => a.shiftId == shiftId && a.shiftRole.roleId == roleId,
|
||||
)
|
||||
.firstOrNull;
|
||||
if (app != null) {
|
||||
@@ -260,8 +266,8 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
clientName: sr.shift.order.business.businessName,
|
||||
logoUrl: sr.shift.order.business.companyLogoUrl,
|
||||
hourlyRate: sr.role.costPerHour,
|
||||
location: sr.shift.order.teamHub.hubName,
|
||||
locationAddress: '',
|
||||
location: sr.shift.location ?? sr.shift.order.teamHub.hubName,
|
||||
locationAddress: sr.shift.locationAddress ?? '',
|
||||
date: startDt?.toIso8601String() ?? '',
|
||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
||||
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 s = result.data.shift;
|
||||
if (s == null) return null;
|
||||
|
||||
|
||||
int? required;
|
||||
int? filled;
|
||||
try {
|
||||
final rolesRes = await _dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute();
|
||||
if (rolesRes.data.shiftRoles.isNotEmpty) {
|
||||
required = 0;
|
||||
filled = 0;
|
||||
for(var r in rolesRes.data.shiftRoles) {
|
||||
required = (required ?? 0) + r.count;
|
||||
filled = (filled ?? 0) + (r.assigned ?? 0);
|
||||
}
|
||||
final rolesRes = await _dataConnect
|
||||
.listShiftRolesByShiftId(shiftId: shiftId)
|
||||
.execute();
|
||||
if (rolesRes.data.shiftRoles.isNotEmpty) {
|
||||
required = 0;
|
||||
filled = 0;
|
||||
for (var r in rolesRes.data.shiftRoles) {
|
||||
required = (required ?? 0) + r.count;
|
||||
filled = (filled ?? 0) + (r.assigned ?? 0);
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
final startDt = _toDateTime(s.startTime);
|
||||
@@ -299,22 +307,22 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
final createdDt = _toDateTime(s.createdAt);
|
||||
|
||||
return Shift(
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
clientName: s.order.business.businessName,
|
||||
logoUrl: null,
|
||||
hourlyRate: s.cost ?? 0.0,
|
||||
location: s.location ?? '',
|
||||
locationAddress: s.locationAddress ?? '',
|
||||
date: startDt?.toIso8601String() ?? '',
|
||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
||||
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
||||
createdDate: createdDt?.toIso8601String() ?? '',
|
||||
status: s.status?.stringValue ?? 'OPEN',
|
||||
description: s.description,
|
||||
durationDays: s.durationDays,
|
||||
requiredSlots: required,
|
||||
filledSlots: filled,
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
clientName: s.order.business.businessName,
|
||||
logoUrl: null,
|
||||
hourlyRate: s.cost ?? 0.0,
|
||||
location: s.location ?? '',
|
||||
locationAddress: s.locationAddress ?? '',
|
||||
date: startDt?.toIso8601String() ?? '',
|
||||
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
||||
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
||||
createdDate: createdDt?.toIso8601String() ?? '',
|
||||
status: s.status?.stringValue ?? 'OPEN',
|
||||
description: s.description,
|
||||
durationDays: s.durationDays,
|
||||
requiredSlots: required,
|
||||
filledSlots: filled,
|
||||
);
|
||||
} catch (e) {
|
||||
return null;
|
||||
@@ -331,8 +339,9 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
|
||||
String targetRoleId = roleId ?? '';
|
||||
if (targetRoleId.isEmpty) {
|
||||
final rolesResult =
|
||||
await _dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute();
|
||||
final rolesResult = await _dataConnect
|
||||
.listShiftRolesByShiftId(shiftId: shiftId)
|
||||
.execute();
|
||||
if (rolesResult.data.shiftRoles.isEmpty) {
|
||||
throw Exception('No open roles for this shift');
|
||||
}
|
||||
@@ -384,10 +393,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
.execute();
|
||||
updatedRole = true;
|
||||
|
||||
await _dataConnect
|
||||
.updateShift(id: shiftId)
|
||||
.filled(filled + 1)
|
||||
.execute();
|
||||
await _dataConnect.updateShift(id: shiftId).filled(filled + 1).execute();
|
||||
updatedShift = true;
|
||||
} catch (e) {
|
||||
if (updatedShift) {
|
||||
@@ -408,15 +414,18 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
|
||||
@override
|
||||
Future<void> acceptShift(String shiftId) async {
|
||||
await _updateApplicationStatus(shiftId, dc.ApplicationStatus.ACCEPTED);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> declineShift(String shiftId) async {
|
||||
await _updateApplicationStatus(shiftId, dc.ApplicationStatus.REJECTED);
|
||||
await _updateApplicationStatus(shiftId, dc.ApplicationStatus.ACCEPTED);
|
||||
}
|
||||
|
||||
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? roleId;
|
||||
|
||||
@@ -427,43 +436,49 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
||||
// Re-check map
|
||||
appId = _shiftToAppIdMap[shiftId];
|
||||
if (appId != null) {
|
||||
roleId = _appToRoleIdMap[appId];
|
||||
roleId = _appToRoleIdMap[appId];
|
||||
} else {
|
||||
// Fallback fetch
|
||||
final staffId = await _getStaffId();
|
||||
final apps = await _dataConnect.getApplicationsByStaffId(staffId: staffId).execute();
|
||||
final app = apps.data.applications.where((a) => a.shiftId == shiftId).firstOrNull;
|
||||
if (app != null) {
|
||||
appId = app.id;
|
||||
roleId = app.shiftRole.id;
|
||||
}
|
||||
// Fallback fetch
|
||||
final staffId = await _getStaffId();
|
||||
final apps = await _dataConnect
|
||||
.getApplicationsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
final app = apps.data.applications
|
||||
.where((a) => a.shiftId == shiftId)
|
||||
.firstOrNull;
|
||||
if (app != null) {
|
||||
appId = app.id;
|
||||
roleId = app.shiftRole.id;
|
||||
}
|
||||
}
|
||||
|
||||
if (appId == null || roleId == null) {
|
||||
// If we are rejecting and can't find an application, create one as rejected (declining an available shift)
|
||||
if (newStatus == dc.ApplicationStatus.REJECTED) {
|
||||
final rolesResult = await _dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute();
|
||||
if (rolesResult.data.shiftRoles.isNotEmpty) {
|
||||
final role = rolesResult.data.shiftRoles.first;
|
||||
final staffId = await _getStaffId();
|
||||
await _dataConnect.createApplication(
|
||||
final rolesResult = await _dataConnect
|
||||
.listShiftRolesByShiftId(shiftId: shiftId)
|
||||
.execute();
|
||||
if (rolesResult.data.shiftRoles.isNotEmpty) {
|
||||
final role = rolesResult.data.shiftRoles.first;
|
||||
final staffId = await _getStaffId();
|
||||
await _dataConnect
|
||||
.createApplication(
|
||||
shiftId: shiftId,
|
||||
staffId: staffId,
|
||||
roleId: role.id,
|
||||
status: dc.ApplicationStatus.REJECTED,
|
||||
origin: dc.ApplicationOrigin.STAFF,
|
||||
).execute();
|
||||
return;
|
||||
}
|
||||
)
|
||||
.execute();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw Exception("Application not found for shift $shiftId");
|
||||
}
|
||||
|
||||
await _dataConnect.updateApplicationStatus(
|
||||
id: appId,
|
||||
roleId: roleId,
|
||||
)
|
||||
.status(newStatus)
|
||||
.execute();
|
||||
await _dataConnect
|
||||
.updateApplicationStatus(id: appId, roleId: roleId)
|
||||
.status(newStatus)
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +123,8 @@ class ShiftDetailsPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<ShiftDetailsBloc>(
|
||||
create: (_) =>
|
||||
Modular.get<ShiftDetailsBloc>()..add(
|
||||
LoadShiftDetailsEvent(
|
||||
shiftId,
|
||||
roleId: shift?.roleId,
|
||||
),
|
||||
),
|
||||
Modular.get<ShiftDetailsBloc>()
|
||||
..add(LoadShiftDetailsEvent(shiftId, roleId: shift?.roleId)),
|
||||
child: BlocListener<ShiftDetailsBloc, ShiftDetailsState>(
|
||||
listener: (context, state) {
|
||||
if (state is ShiftActionSuccess) {
|
||||
@@ -140,12 +136,14 @@ class ShiftDetailsPage extends StatelessWidget {
|
||||
);
|
||||
Modular.to.navigateToShiftsHome();
|
||||
} else if (state is ShiftDetailsError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.message),
|
||||
backgroundColor: const Color(0xFFEF4444),
|
||||
),
|
||||
);
|
||||
if (shift == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.message),
|
||||
backgroundColor: const Color(0xFFEF4444),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: BlocBuilder<ShiftDetailsBloc, ShiftDetailsState>(
|
||||
@@ -180,7 +178,7 @@ class ShiftDetailsPage extends StatelessWidget {
|
||||
appBar: UiAppBar(
|
||||
title: displayShift.title,
|
||||
centerTitle: false,
|
||||
onLeadingPressed:() => Modular.to.navigateToShiftsHome(),
|
||||
onLeadingPressed: () => Modular.to.navigateToShiftsHome(),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
@@ -403,14 +401,14 @@ class ShiftDetailsPage extends StatelessWidget {
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
displayShift.location.isEmpty
|
||||
? "TBD"
|
||||
: displayShift.locationAddress,
|
||||
style: UiTypography.title1m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
displayShift.location.isEmpty
|
||||
? "TBD"
|
||||
: displayShift.locationAddress,
|
||||
style: UiTypography.title1m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -135,10 +135,7 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
|
||||
final visibleMyShifts = widget.myShifts.where((s) {
|
||||
try {
|
||||
final date = DateTime.parse(s.date);
|
||||
return date.isAfter(
|
||||
weekStartDate.subtract(const Duration(seconds: 1)),
|
||||
) &&
|
||||
date.isBefore(weekEndDate.add(const Duration(days: 1)));
|
||||
return _isSameDay(date, _selectedDate);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user