Merge pull request #444 from Oloodi/staff_recurring_permanent_order
Staff recurring permanent order
This commit is contained in:
@@ -98,7 +98,11 @@ extension StaffNavigator on IModularNavigator {
|
|||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// * [selectedDate] - Optional date to pre-select in the shifts view
|
/// * [selectedDate] - Optional date to pre-select in the shifts view
|
||||||
/// * [initialTab] - Optional initial tab (via query parameter)
|
/// * [initialTab] - Optional initial tab (via query parameter)
|
||||||
void toShifts({DateTime? selectedDate, String? initialTab}) {
|
void toShifts({
|
||||||
|
DateTime? selectedDate,
|
||||||
|
String? initialTab,
|
||||||
|
bool? refreshAvailable,
|
||||||
|
}) {
|
||||||
final Map<String, dynamic> args = <String, dynamic>{};
|
final Map<String, dynamic> args = <String, dynamic>{};
|
||||||
if (selectedDate != null) {
|
if (selectedDate != null) {
|
||||||
args['selectedDate'] = selectedDate;
|
args['selectedDate'] = selectedDate;
|
||||||
@@ -106,6 +110,9 @@ extension StaffNavigator on IModularNavigator {
|
|||||||
if (initialTab != null) {
|
if (initialTab != null) {
|
||||||
args['initialTab'] = initialTab;
|
args['initialTab'] = initialTab;
|
||||||
}
|
}
|
||||||
|
if (refreshAvailable == true) {
|
||||||
|
args['refreshAvailable'] = true;
|
||||||
|
}
|
||||||
navigate(
|
navigate(
|
||||||
StaffPaths.shifts,
|
StaffPaths.shifts,
|
||||||
arguments: args.isEmpty ? null : args,
|
arguments: args.isEmpty ? null : args,
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ class Shift extends Equatable {
|
|||||||
final bool? hasApplied;
|
final bool? hasApplied;
|
||||||
final double? totalValue;
|
final double? totalValue;
|
||||||
final Break? breakInfo;
|
final Break? breakInfo;
|
||||||
|
final String? orderId;
|
||||||
|
final String? orderType;
|
||||||
|
final List<ShiftSchedule>? schedules;
|
||||||
|
|
||||||
const Shift({
|
const Shift({
|
||||||
required this.id,
|
required this.id,
|
||||||
@@ -62,6 +65,9 @@ class Shift extends Equatable {
|
|||||||
this.hasApplied,
|
this.hasApplied,
|
||||||
this.totalValue,
|
this.totalValue,
|
||||||
this.breakInfo,
|
this.breakInfo,
|
||||||
|
this.orderId,
|
||||||
|
this.orderType,
|
||||||
|
this.schedules,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -95,9 +101,27 @@ class Shift extends Equatable {
|
|||||||
hasApplied,
|
hasApplied,
|
||||||
totalValue,
|
totalValue,
|
||||||
breakInfo,
|
breakInfo,
|
||||||
|
orderId,
|
||||||
|
orderType,
|
||||||
|
schedules,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShiftSchedule extends Equatable {
|
||||||
|
const ShiftSchedule({
|
||||||
|
required this.date,
|
||||||
|
required this.startTime,
|
||||||
|
required this.endTime,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String date;
|
||||||
|
final String startTime;
|
||||||
|
final String endTime;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => <Object?>[date, startTime, endTime];
|
||||||
|
}
|
||||||
|
|
||||||
class ShiftManager extends Equatable {
|
class ShiftManager extends Equatable {
|
||||||
const ShiftManager({required this.name, required this.phone, this.avatar});
|
const ShiftManager({required this.name, required this.phone, this.avatar});
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
.state(hub.state)
|
.state(hub.state)
|
||||||
.street(hub.street)
|
.street(hub.street)
|
||||||
.country(hub.country)
|
.country(hub.country)
|
||||||
.status(dc.ShiftStatus.CONFIRMED)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
@@ -224,7 +224,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
.state(hub.state)
|
.state(hub.state)
|
||||||
.street(hub.street)
|
.street(hub.street)
|
||||||
.country(hub.country)
|
.country(hub.country)
|
||||||
.status(dc.ShiftStatus.CONFIRMED)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
@@ -342,7 +342,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
.state(hub.state)
|
.state(hub.state)
|
||||||
.street(hub.street)
|
.street(hub.street)
|
||||||
.country(hub.country)
|
.country(hub.country)
|
||||||
.status(dc.ShiftStatus.CONFIRMED)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
|
|||||||
@@ -20,6 +20,42 @@ class PermanentOrderView extends StatelessWidget {
|
|||||||
/// Creates a [PermanentOrderView].
|
/// Creates a [PermanentOrderView].
|
||||||
const PermanentOrderView({super.key});
|
const PermanentOrderView({super.key});
|
||||||
|
|
||||||
|
DateTime _firstPermanentShiftDate(
|
||||||
|
DateTime startDate,
|
||||||
|
List<String> permanentDays,
|
||||||
|
) {
|
||||||
|
final DateTime start = DateTime(startDate.year, startDate.month, startDate.day);
|
||||||
|
final DateTime end = start.add(const Duration(days: 29));
|
||||||
|
final Set<String> selected = permanentDays.toSet();
|
||||||
|
for (DateTime day = start; !day.isAfter(end); day = day.add(const Duration(days: 1))) {
|
||||||
|
if (selected.contains(_weekdayLabel(day))) {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _weekdayLabel(DateTime date) {
|
||||||
|
switch (date.weekday) {
|
||||||
|
case DateTime.monday:
|
||||||
|
return 'MON';
|
||||||
|
case DateTime.tuesday:
|
||||||
|
return 'TUE';
|
||||||
|
case DateTime.wednesday:
|
||||||
|
return 'WED';
|
||||||
|
case DateTime.thursday:
|
||||||
|
return 'THU';
|
||||||
|
case DateTime.friday:
|
||||||
|
return 'FRI';
|
||||||
|
case DateTime.saturday:
|
||||||
|
return 'SAT';
|
||||||
|
case DateTime.sunday:
|
||||||
|
return 'SUN';
|
||||||
|
default:
|
||||||
|
return 'SUN';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TranslationsClientCreateOrderPermanentEn labels =
|
final TranslationsClientCreateOrderPermanentEn labels =
|
||||||
@@ -42,6 +78,10 @@ class PermanentOrderView extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
builder: (BuildContext context, PermanentOrderState state) {
|
builder: (BuildContext context, PermanentOrderState state) {
|
||||||
if (state.status == PermanentOrderStatus.success) {
|
if (state.status == PermanentOrderStatus.success) {
|
||||||
|
final DateTime initialDate = _firstPermanentShiftDate(
|
||||||
|
state.startDate,
|
||||||
|
state.permanentDays,
|
||||||
|
);
|
||||||
return PermanentOrderSuccessView(
|
return PermanentOrderSuccessView(
|
||||||
title: labels.title,
|
title: labels.title,
|
||||||
message: labels.subtitle,
|
message: labels.subtitle,
|
||||||
@@ -50,7 +90,7 @@ class PermanentOrderView extends StatelessWidget {
|
|||||||
ClientPaths.orders,
|
ClientPaths.orders,
|
||||||
(_) => false,
|
(_) => false,
|
||||||
arguments: <String, dynamic>{
|
arguments: <String, dynamic>{
|
||||||
'initialDate': state.startDate.toIso8601String(),
|
'initialDate': initialDate.toIso8601String(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,6 +20,43 @@ class RecurringOrderView extends StatelessWidget {
|
|||||||
/// Creates a [RecurringOrderView].
|
/// Creates a [RecurringOrderView].
|
||||||
const RecurringOrderView({super.key});
|
const RecurringOrderView({super.key});
|
||||||
|
|
||||||
|
DateTime _firstRecurringShiftDate(
|
||||||
|
DateTime startDate,
|
||||||
|
DateTime endDate,
|
||||||
|
List<String> recurringDays,
|
||||||
|
) {
|
||||||
|
final DateTime start = DateTime(startDate.year, startDate.month, startDate.day);
|
||||||
|
final DateTime end = DateTime(endDate.year, endDate.month, endDate.day);
|
||||||
|
final Set<String> selected = recurringDays.toSet();
|
||||||
|
for (DateTime day = start; !day.isAfter(end); day = day.add(const Duration(days: 1))) {
|
||||||
|
if (selected.contains(_weekdayLabel(day))) {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _weekdayLabel(DateTime date) {
|
||||||
|
switch (date.weekday) {
|
||||||
|
case DateTime.monday:
|
||||||
|
return 'MON';
|
||||||
|
case DateTime.tuesday:
|
||||||
|
return 'TUE';
|
||||||
|
case DateTime.wednesday:
|
||||||
|
return 'WED';
|
||||||
|
case DateTime.thursday:
|
||||||
|
return 'THU';
|
||||||
|
case DateTime.friday:
|
||||||
|
return 'FRI';
|
||||||
|
case DateTime.saturday:
|
||||||
|
return 'SAT';
|
||||||
|
case DateTime.sunday:
|
||||||
|
return 'SUN';
|
||||||
|
default:
|
||||||
|
return 'SUN';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TranslationsClientCreateOrderRecurringEn labels =
|
final TranslationsClientCreateOrderRecurringEn labels =
|
||||||
@@ -44,6 +81,15 @@ class RecurringOrderView extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
builder: (BuildContext context, RecurringOrderState state) {
|
builder: (BuildContext context, RecurringOrderState state) {
|
||||||
if (state.status == RecurringOrderStatus.success) {
|
if (state.status == RecurringOrderStatus.success) {
|
||||||
|
final DateTime maxEndDate =
|
||||||
|
state.startDate.add(const Duration(days: 29));
|
||||||
|
final DateTime effectiveEndDate =
|
||||||
|
state.endDate.isAfter(maxEndDate) ? maxEndDate : state.endDate;
|
||||||
|
final DateTime initialDate = _firstRecurringShiftDate(
|
||||||
|
state.startDate,
|
||||||
|
effectiveEndDate,
|
||||||
|
state.recurringDays,
|
||||||
|
);
|
||||||
return RecurringOrderSuccessView(
|
return RecurringOrderSuccessView(
|
||||||
title: labels.title,
|
title: labels.title,
|
||||||
message: labels.subtitle,
|
message: labels.subtitle,
|
||||||
@@ -52,7 +98,7 @@ class RecurringOrderView extends StatelessWidget {
|
|||||||
ClientPaths.orders,
|
ClientPaths.orders,
|
||||||
(_) => false,
|
(_) => false,
|
||||||
arguments: <String, dynamic>{
|
arguments: <String, dynamic>{
|
||||||
'initialDate': state.startDate.toIso8601String(),
|
'initialDate': initialDate.toIso8601String(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
.state(selectedHub.state)
|
.state(selectedHub.state)
|
||||||
.street(selectedHub.street)
|
.street(selectedHub.street)
|
||||||
.country(selectedHub.country)
|
.country(selectedHub.country)
|
||||||
.status(dc.ShiftStatus.PENDING)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
|
|||||||
@@ -95,11 +95,12 @@ class ShiftsRepositoryImpl
|
|||||||
DateTime? end,
|
DateTime? end,
|
||||||
}) async {
|
}) async {
|
||||||
final staffId = await _service.getStaffId();
|
final staffId = await _service.getStaffId();
|
||||||
var query = _service.connector.getApplicationsByStaffId(staffId: staffId);
|
var query = _service.connector.getMyApplicationsByStaffId(staffId: staffId);
|
||||||
if (start != null && end != null) {
|
if (start != null && end != null) {
|
||||||
query = query.dayStart(_service.toTimestamp(start)).dayEnd(_service.toTimestamp(end));
|
query = query.dayStart(_service.toTimestamp(start)).dayEnd(_service.toTimestamp(end));
|
||||||
}
|
}
|
||||||
final fdc.QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> response = await _service.executeProtected(() => query.execute());
|
final fdc.QueryResult<dc.GetMyApplicationsByStaffIdData, dc.GetMyApplicationsByStaffIdVariables> response =
|
||||||
|
await _service.executeProtected(() => query.execute());
|
||||||
|
|
||||||
final apps = response.data.applications;
|
final apps = response.data.applications;
|
||||||
final List<Shift> shifts = [];
|
final List<Shift> shifts = [];
|
||||||
@@ -229,6 +230,8 @@ class ShiftsRepositoryImpl
|
|||||||
filledSlots: sr.assigned ?? 0,
|
filledSlots: sr.assigned ?? 0,
|
||||||
latitude: sr.shift.latitude,
|
latitude: sr.shift.latitude,
|
||||||
longitude: sr.shift.longitude,
|
longitude: sr.shift.longitude,
|
||||||
|
orderId: sr.shift.order.id,
|
||||||
|
orderType: sr.shift.order.orderType?.stringValue,
|
||||||
breakInfo: BreakAdapter.fromData(
|
breakInfo: BreakAdapter.fromData(
|
||||||
isPaid: sr.isBreakPaid ?? false,
|
isPaid: sr.isBreakPaid ?? false,
|
||||||
breakTime: sr.breakType?.stringValue,
|
breakTime: sr.breakType?.stringValue,
|
||||||
|
|||||||
@@ -112,9 +112,15 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState>
|
|||||||
) async {
|
) async {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is! ShiftsLoaded) return;
|
if (currentState is! ShiftsLoaded) return;
|
||||||
if (currentState.availableLoading || currentState.availableLoaded) return;
|
if (!event.force &&
|
||||||
|
(currentState.availableLoading || currentState.availableLoaded)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit(currentState.copyWith(availableLoading: true));
|
emit(currentState.copyWith(
|
||||||
|
availableLoading: true,
|
||||||
|
availableLoaded: false,
|
||||||
|
));
|
||||||
await handleError(
|
await handleError(
|
||||||
emit: emit,
|
emit: emit,
|
||||||
action: () async {
|
action: () async {
|
||||||
|
|||||||
@@ -12,7 +12,13 @@ class LoadShiftsEvent extends ShiftsEvent {}
|
|||||||
|
|
||||||
class LoadHistoryShiftsEvent extends ShiftsEvent {}
|
class LoadHistoryShiftsEvent extends ShiftsEvent {}
|
||||||
|
|
||||||
class LoadAvailableShiftsEvent extends ShiftsEvent {}
|
class LoadAvailableShiftsEvent extends ShiftsEvent {
|
||||||
|
final bool force;
|
||||||
|
const LoadAvailableShiftsEvent({this.force = false});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [force];
|
||||||
|
}
|
||||||
|
|
||||||
class LoadFindFirstEvent extends ShiftsEvent {}
|
class LoadFindFirstEvent extends ShiftsEvent {}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,11 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
|||||||
message: state.message,
|
message: state.message,
|
||||||
type: UiSnackbarType.success,
|
type: UiSnackbarType.success,
|
||||||
);
|
);
|
||||||
Modular.to.toShifts(selectedDate: state.shiftDate);
|
Modular.to.toShifts(
|
||||||
|
selectedDate: state.shiftDate,
|
||||||
|
initialTab: 'find',
|
||||||
|
refreshAvailable: true,
|
||||||
|
);
|
||||||
} else if (state is ShiftDetailsError) {
|
} else if (state is ShiftDetailsError) {
|
||||||
if (_isApplying) {
|
if (_isApplying) {
|
||||||
UiSnackbar.show(
|
UiSnackbar.show(
|
||||||
@@ -112,7 +116,8 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shift displayShift = widget.shift;
|
final Shift displayShift =
|
||||||
|
state is ShiftDetailsLoaded ? state.shift : widget.shift;
|
||||||
final i18n = Translations.of(context).staff_shifts.shift_details;
|
final i18n = Translations.of(context).staff_shifts.shift_details;
|
||||||
|
|
||||||
final duration = _calculateDuration(displayShift);
|
final duration = _calculateDuration(displayShift);
|
||||||
|
|||||||
@@ -12,7 +12,13 @@ import '../widgets/tabs/history_shifts_tab.dart';
|
|||||||
class ShiftsPage extends StatefulWidget {
|
class ShiftsPage extends StatefulWidget {
|
||||||
final String? initialTab;
|
final String? initialTab;
|
||||||
final DateTime? selectedDate;
|
final DateTime? selectedDate;
|
||||||
const ShiftsPage({super.key, this.initialTab, this.selectedDate});
|
final bool refreshAvailable;
|
||||||
|
const ShiftsPage({
|
||||||
|
super.key,
|
||||||
|
this.initialTab,
|
||||||
|
this.selectedDate,
|
||||||
|
this.refreshAvailable = false,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ShiftsPage> createState() => _ShiftsPageState();
|
State<ShiftsPage> createState() => _ShiftsPageState();
|
||||||
@@ -22,6 +28,8 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
late String _activeTab;
|
late String _activeTab;
|
||||||
DateTime? _selectedDate;
|
DateTime? _selectedDate;
|
||||||
bool _prioritizeFind = false;
|
bool _prioritizeFind = false;
|
||||||
|
bool _refreshAvailable = false;
|
||||||
|
bool _pendingAvailableRefresh = false;
|
||||||
final ShiftsBloc _bloc = Modular.get<ShiftsBloc>();
|
final ShiftsBloc _bloc = Modular.get<ShiftsBloc>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -30,6 +38,8 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
_activeTab = widget.initialTab ?? 'myshifts';
|
_activeTab = widget.initialTab ?? 'myshifts';
|
||||||
_selectedDate = widget.selectedDate;
|
_selectedDate = widget.selectedDate;
|
||||||
_prioritizeFind = widget.initialTab == 'find';
|
_prioritizeFind = widget.initialTab == 'find';
|
||||||
|
_refreshAvailable = widget.refreshAvailable;
|
||||||
|
_pendingAvailableRefresh = widget.refreshAvailable;
|
||||||
if (_prioritizeFind) {
|
if (_prioritizeFind) {
|
||||||
_bloc.add(LoadFindFirstEvent());
|
_bloc.add(LoadFindFirstEvent());
|
||||||
} else {
|
} else {
|
||||||
@@ -40,7 +50,9 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
}
|
}
|
||||||
if (_activeTab == 'find') {
|
if (_activeTab == 'find') {
|
||||||
if (!_prioritizeFind) {
|
if (!_prioritizeFind) {
|
||||||
_bloc.add(LoadAvailableShiftsEvent());
|
_bloc.add(
|
||||||
|
LoadAvailableShiftsEvent(force: _refreshAvailable),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check profile completion
|
// Check profile completion
|
||||||
@@ -61,6 +73,10 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
_selectedDate = widget.selectedDate;
|
_selectedDate = widget.selectedDate;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (widget.refreshAvailable) {
|
||||||
|
_refreshAvailable = true;
|
||||||
|
_pendingAvailableRefresh = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -79,6 +95,10 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
if (_pendingAvailableRefresh && state is ShiftsLoaded) {
|
||||||
|
_pendingAvailableRefresh = false;
|
||||||
|
_bloc.add(const LoadAvailableShiftsEvent(force: true));
|
||||||
|
}
|
||||||
final bool baseLoaded = state is ShiftsLoaded;
|
final bool baseLoaded = state is ShiftsLoaded;
|
||||||
final List<Shift> myShifts = (state is ShiftsLoaded)
|
final List<Shift> myShifts = (state is ShiftsLoaded)
|
||||||
? state.myShifts
|
? state.myShifts
|
||||||
|
|||||||
@@ -77,6 +77,13 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
|||||||
String _getShiftType() {
|
String _getShiftType() {
|
||||||
// Handling potential localization key availability
|
// Handling potential localization key availability
|
||||||
try {
|
try {
|
||||||
|
final String orderType = (widget.shift.orderType ?? '').toUpperCase();
|
||||||
|
if (orderType == 'PERMANENT') {
|
||||||
|
return t.staff_shifts.filter.long_term;
|
||||||
|
}
|
||||||
|
if (orderType == 'RECURRING') {
|
||||||
|
return t.staff_shifts.filter.multi_day;
|
||||||
|
}
|
||||||
if (widget.shift.durationDays != null && widget.shift.durationDays! > 30) {
|
if (widget.shift.durationDays != null && widget.shift.durationDays! > 30) {
|
||||||
return t.staff_shifts.filter.long_term;
|
return t.staff_shifts.filter.long_term;
|
||||||
}
|
}
|
||||||
@@ -133,6 +140,24 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
|||||||
statusText = status?.toUpperCase() ?? "";
|
statusText = status?.toUpperCase() ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final schedules = widget.shift.schedules ?? <ShiftSchedule>[];
|
||||||
|
final hasSchedules = schedules.isNotEmpty;
|
||||||
|
final List<ShiftSchedule> visibleSchedules = schedules.length <= 5
|
||||||
|
? schedules
|
||||||
|
: schedules.take(3).toList();
|
||||||
|
final int remainingSchedules =
|
||||||
|
schedules.length <= 5 ? 0 : schedules.length - 3;
|
||||||
|
final String scheduleRange = hasSchedules
|
||||||
|
? () {
|
||||||
|
final first = schedules.first.date;
|
||||||
|
final last = schedules.last.date;
|
||||||
|
if (first == last) {
|
||||||
|
return _formatDate(first);
|
||||||
|
}
|
||||||
|
return '${_formatDate(first)} – ${_formatDate(last)}';
|
||||||
|
}()
|
||||||
|
: '';
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Modular.to.pushNamed(
|
Modular.to.pushNamed(
|
||||||
@@ -191,8 +216,8 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
|||||||
letterSpacing: 0.5,
|
letterSpacing: 0.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Shift Type Badge
|
// Shift Type Badge (Order type)
|
||||||
if (status == 'open' || status == 'pending') ...[
|
if ((widget.shift.orderType ?? '').isNotEmpty) ...[
|
||||||
const SizedBox(width: UiConstants.space2),
|
const SizedBox(width: UiConstants.space2),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -200,13 +225,14 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
|||||||
vertical: 2,
|
vertical: 2,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: UiColors.primary.withValues(alpha: 0.1),
|
color: UiColors.background,
|
||||||
borderRadius: UiConstants.radiusSm,
|
borderRadius: UiConstants.radiusSm,
|
||||||
|
border: Border.all(color: UiColors.border),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_getShiftType(),
|
_getShiftType(),
|
||||||
style: UiTypography.footnote2m.copyWith(
|
style: UiTypography.footnote2m.copyWith(
|
||||||
color: UiColors.primary,
|
color: UiColors.textSecondary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -299,7 +325,55 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
|||||||
const SizedBox(height: UiConstants.space2),
|
const SizedBox(height: UiConstants.space2),
|
||||||
|
|
||||||
// Date & Time
|
// Date & Time
|
||||||
if (widget.shift.durationDays != null &&
|
if (hasSchedules) ...[
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
UiIcons.clock,
|
||||||
|
size: UiConstants.iconXs,
|
||||||
|
color: UiColors.primary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: UiConstants.space1),
|
||||||
|
Text(
|
||||||
|
'${schedules.length} schedules',
|
||||||
|
style: UiTypography.footnote2m.copyWith(
|
||||||
|
color: UiColors.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space1),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 2),
|
||||||
|
child: Text(
|
||||||
|
scheduleRange,
|
||||||
|
style: UiTypography.footnote2r.copyWith(color: UiColors.primary),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...visibleSchedules.map(
|
||||||
|
(schedule) => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 2),
|
||||||
|
child: Text(
|
||||||
|
'${_formatDate(schedule.date)}, ${_formatTime(schedule.startTime)} – ${_formatTime(schedule.endTime)}',
|
||||||
|
style: UiTypography.footnote2r.copyWith(
|
||||||
|
color: UiColors.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (remainingSchedules > 0)
|
||||||
|
Text(
|
||||||
|
'+$remainingSchedules more schedules',
|
||||||
|
style: UiTypography.footnote2r.copyWith(
|
||||||
|
color: UiColors.primary.withOpacity(0.7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
] else if (widget.shift.durationDays != null &&
|
||||||
widget.shift.durationDays! > 1) ...[
|
widget.shift.durationDays! > 1) ...[
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -327,13 +401,18 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
|||||||
padding: const EdgeInsets.only(bottom: 2),
|
padding: const EdgeInsets.only(bottom: 2),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${_formatDate(widget.shift.date)}, ${_formatTime(widget.shift.startTime)} – ${_formatTime(widget.shift.endTime)}',
|
'${_formatDate(widget.shift.date)}, ${_formatTime(widget.shift.startTime)} – ${_formatTime(widget.shift.endTime)}',
|
||||||
style: UiTypography.footnote2r.copyWith(color: UiColors.primary),
|
style: UiTypography.footnote2r.copyWith(
|
||||||
|
color: UiColors.primary,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.shift.durationDays! > 1)
|
if (widget.shift.durationDays! > 1)
|
||||||
Text(
|
Text(
|
||||||
'... +${widget.shift.durationDays! - 1} more days',
|
'... +${widget.shift.durationDays! - 1} more days',
|
||||||
style: UiTypography.footnote2r.copyWith(color: UiColors.primary.withOpacity(0.7)),
|
style: UiTypography.footnote2r.copyWith(
|
||||||
|
color:
|
||||||
|
UiColors.primary.withOpacity(0.7),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -20,6 +20,119 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
|
|||||||
String _searchQuery = '';
|
String _searchQuery = '';
|
||||||
String _jobType = 'all';
|
String _jobType = 'all';
|
||||||
|
|
||||||
|
bool _isRecurring(Shift shift) =>
|
||||||
|
(shift.orderType ?? '').toUpperCase() == 'RECURRING';
|
||||||
|
|
||||||
|
bool _isPermanent(Shift shift) =>
|
||||||
|
(shift.orderType ?? '').toUpperCase() == 'PERMANENT';
|
||||||
|
|
||||||
|
DateTime? _parseShiftDate(String date) {
|
||||||
|
if (date.isEmpty) return null;
|
||||||
|
try {
|
||||||
|
return DateTime.parse(date);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Shift> _groupMultiDayShifts(List<Shift> shifts) {
|
||||||
|
final Map<String, List<Shift>> grouped = <String, List<Shift>>{};
|
||||||
|
for (final shift in shifts) {
|
||||||
|
if (!_isRecurring(shift) && !_isPermanent(shift)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final orderId = shift.orderId;
|
||||||
|
final roleId = shift.roleId;
|
||||||
|
if (orderId == null || roleId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final key = '$orderId::$roleId';
|
||||||
|
grouped.putIfAbsent(key, () => <Shift>[]).add(shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<String> addedGroups = <String>{};
|
||||||
|
final List<Shift> result = <Shift>[];
|
||||||
|
|
||||||
|
for (final shift in shifts) {
|
||||||
|
if (!_isRecurring(shift) && !_isPermanent(shift)) {
|
||||||
|
result.add(shift);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final orderId = shift.orderId;
|
||||||
|
final roleId = shift.roleId;
|
||||||
|
if (orderId == null || roleId == null) {
|
||||||
|
result.add(shift);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final key = '$orderId::$roleId';
|
||||||
|
if (addedGroups.contains(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addedGroups.add(key);
|
||||||
|
final List<Shift> group = grouped[key] ?? <Shift>[];
|
||||||
|
if (group.isEmpty) {
|
||||||
|
result.add(shift);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
group.sort((a, b) {
|
||||||
|
final ad = _parseShiftDate(a.date);
|
||||||
|
final bd = _parseShiftDate(b.date);
|
||||||
|
if (ad == null && bd == null) return 0;
|
||||||
|
if (ad == null) return 1;
|
||||||
|
if (bd == null) return -1;
|
||||||
|
return ad.compareTo(bd);
|
||||||
|
});
|
||||||
|
|
||||||
|
final Shift first = group.first;
|
||||||
|
final List<ShiftSchedule> schedules = group
|
||||||
|
.map((s) => ShiftSchedule(
|
||||||
|
date: s.date,
|
||||||
|
startTime: s.startTime,
|
||||||
|
endTime: s.endTime,
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
result.add(
|
||||||
|
Shift(
|
||||||
|
id: first.id,
|
||||||
|
roleId: first.roleId,
|
||||||
|
title: first.title,
|
||||||
|
clientName: first.clientName,
|
||||||
|
logoUrl: first.logoUrl,
|
||||||
|
hourlyRate: first.hourlyRate,
|
||||||
|
location: first.location,
|
||||||
|
locationAddress: first.locationAddress,
|
||||||
|
date: first.date,
|
||||||
|
startTime: first.startTime,
|
||||||
|
endTime: first.endTime,
|
||||||
|
createdDate: first.createdDate,
|
||||||
|
tipsAvailable: first.tipsAvailable,
|
||||||
|
travelTime: first.travelTime,
|
||||||
|
mealProvided: first.mealProvided,
|
||||||
|
parkingAvailable: first.parkingAvailable,
|
||||||
|
gasCompensation: first.gasCompensation,
|
||||||
|
description: first.description,
|
||||||
|
instructions: first.instructions,
|
||||||
|
managers: first.managers,
|
||||||
|
latitude: first.latitude,
|
||||||
|
longitude: first.longitude,
|
||||||
|
status: first.status,
|
||||||
|
durationDays: schedules.length,
|
||||||
|
requiredSlots: first.requiredSlots,
|
||||||
|
filledSlots: first.filledSlots,
|
||||||
|
hasApplied: first.hasApplied,
|
||||||
|
totalValue: first.totalValue,
|
||||||
|
breakInfo: first.breakInfo,
|
||||||
|
orderId: first.orderId,
|
||||||
|
orderType: first.orderType,
|
||||||
|
schedules: schedules,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildFilterTab(String id, String label) {
|
Widget _buildFilterTab(String id, String label) {
|
||||||
final isSelected = _jobType == id;
|
final isSelected = _jobType == id;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
@@ -49,8 +162,10 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final groupedJobs = _groupMultiDayShifts(widget.availableJobs);
|
||||||
|
|
||||||
// Filter logic
|
// Filter logic
|
||||||
final filteredJobs = widget.availableJobs.where((s) {
|
final filteredJobs = groupedJobs.where((s) {
|
||||||
final matchesSearch =
|
final matchesSearch =
|
||||||
s.title.toLowerCase().contains(_searchQuery.toLowerCase()) ||
|
s.title.toLowerCase().contains(_searchQuery.toLowerCase()) ||
|
||||||
s.location.toLowerCase().contains(_searchQuery.toLowerCase()) ||
|
s.location.toLowerCase().contains(_searchQuery.toLowerCase()) ||
|
||||||
@@ -60,10 +175,15 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
|
|||||||
|
|
||||||
if (_jobType == 'all') return true;
|
if (_jobType == 'all') return true;
|
||||||
if (_jobType == 'one-day') {
|
if (_jobType == 'one-day') {
|
||||||
|
if (_isRecurring(s) || _isPermanent(s)) return false;
|
||||||
return s.durationDays == null || s.durationDays! <= 1;
|
return s.durationDays == null || s.durationDays! <= 1;
|
||||||
}
|
}
|
||||||
if (_jobType == 'multi-day') {
|
if (_jobType == 'multi-day') {
|
||||||
return s.durationDays != null && s.durationDays! > 1;
|
return _isRecurring(s) ||
|
||||||
|
(s.durationDays != null && s.durationDays! > 1);
|
||||||
|
}
|
||||||
|
if (_jobType == 'long-term') {
|
||||||
|
return _isPermanent(s);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class StaffShiftsModule extends Module {
|
|||||||
return ShiftsPage(
|
return ShiftsPage(
|
||||||
initialTab: queryParams['tab'] ?? args?['initialTab'],
|
initialTab: queryParams['tab'] ?? args?['initialTab'],
|
||||||
selectedDate: args?['selectedDate'],
|
selectedDate: args?['selectedDate'],
|
||||||
|
refreshAvailable: args?['refreshAvailable'] == true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -356,6 +356,95 @@ query getApplicationsByStaffId(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query getMyApplicationsByStaffId(
|
||||||
|
$staffId: UUID!
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
$dayStart: Timestamp
|
||||||
|
$dayEnd: Timestamp
|
||||||
|
) @auth(level: USER) {
|
||||||
|
applications(
|
||||||
|
where: {
|
||||||
|
staffId: { eq: $staffId }
|
||||||
|
status: { in: [ CONFIRMED, CHECKED_IN, CHECKED_OUT, LATE, PENDING] }
|
||||||
|
shift: {
|
||||||
|
date: { ge: $dayStart, le: $dayEnd }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
shiftId
|
||||||
|
staffId
|
||||||
|
status
|
||||||
|
appliedAt
|
||||||
|
checkInTime
|
||||||
|
checkOutTime
|
||||||
|
origin
|
||||||
|
createdAt
|
||||||
|
|
||||||
|
shift {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
date
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
location
|
||||||
|
status
|
||||||
|
durationDays
|
||||||
|
description
|
||||||
|
latitude
|
||||||
|
longitude
|
||||||
|
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
eventName
|
||||||
|
#location
|
||||||
|
|
||||||
|
teamHub {
|
||||||
|
address
|
||||||
|
placeId
|
||||||
|
hubName
|
||||||
|
}
|
||||||
|
|
||||||
|
business {
|
||||||
|
id
|
||||||
|
businessName
|
||||||
|
email
|
||||||
|
contactName
|
||||||
|
companyLogoUrl
|
||||||
|
}
|
||||||
|
vendor {
|
||||||
|
id
|
||||||
|
companyName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftRole {
|
||||||
|
id
|
||||||
|
roleId
|
||||||
|
count
|
||||||
|
assigned
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
hours
|
||||||
|
breakType
|
||||||
|
isBreakPaid
|
||||||
|
totalValue
|
||||||
|
role {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
costPerHour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query vaidateDayStaffApplication(
|
query vaidateDayStaffApplication(
|
||||||
$staffId: UUID!
|
$staffId: UUID!
|
||||||
$offset: Int
|
$offset: Int
|
||||||
@@ -695,10 +784,14 @@ query listCompletedApplicationsByStaffId(
|
|||||||
durationDays
|
durationDays
|
||||||
latitude
|
latitude
|
||||||
longitude
|
longitude
|
||||||
|
orderId
|
||||||
|
|
||||||
order {
|
order {
|
||||||
id
|
id
|
||||||
eventName
|
eventName
|
||||||
|
orderType
|
||||||
|
startDate
|
||||||
|
endDate
|
||||||
|
|
||||||
teamHub {
|
teamHub {
|
||||||
address
|
address
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ query listShiftRolesByVendorId(
|
|||||||
shiftRoles(
|
shiftRoles(
|
||||||
where: {
|
where: {
|
||||||
shift: {
|
shift: {
|
||||||
status: {in: [IN_PROGRESS, CONFIRMED, ASSIGNED, OPEN, PENDING]} #IN_PROGRESS? PENDING?
|
status: {in: [IN_PROGRESS, ASSIGNED, OPEN]} #IN_PROGRESS?
|
||||||
order: {
|
order: {
|
||||||
vendorId: { eq: $vendorId }
|
vendorId: { eq: $vendorId }
|
||||||
}
|
}
|
||||||
@@ -511,7 +511,7 @@ query getCompletedShiftsByBusinessId(
|
|||||||
shifts(
|
shifts(
|
||||||
where: {
|
where: {
|
||||||
order: { businessId: { eq: $businessId } }
|
order: { businessId: { eq: $businessId } }
|
||||||
status: {in: [IN_PROGRESS, CONFIRMED, COMPLETED, OPEN]}
|
status: {in: [IN_PROGRESS, COMPLETED, OPEN]}
|
||||||
date: { ge: $dateFrom, le: $dateTo }
|
date: { ge: $dateFrom, le: $dateTo }
|
||||||
}
|
}
|
||||||
offset: $offset
|
offset: $offset
|
||||||
|
|||||||
@@ -927,7 +927,7 @@ mutation seedAll @transaction {
|
|||||||
placeId: "Eiw0MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
placeId: "Eiw0MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
||||||
latitude: 34.2611486
|
latitude: 34.2611486
|
||||||
longitude: -118.5010287
|
longitude: -118.5010287
|
||||||
status: ASSIGNED
|
status: OPEN
|
||||||
workersNeeded: 2
|
workersNeeded: 2
|
||||||
filled: 1
|
filled: 1
|
||||||
}
|
}
|
||||||
@@ -950,7 +950,7 @@ mutation seedAll @transaction {
|
|||||||
placeId: "Eiw2ODAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
placeId: "Eiw2ODAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
||||||
latitude: 34.2611486
|
latitude: 34.2611486
|
||||||
longitude: -118.5010287
|
longitude: -118.5010287
|
||||||
status: ASSIGNED
|
status: OPEN
|
||||||
workersNeeded: 2
|
workersNeeded: 2
|
||||||
filled: 1
|
filled: 1
|
||||||
}
|
}
|
||||||
@@ -996,7 +996,7 @@ mutation seedAll @transaction {
|
|||||||
placeId: "Eiw0MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
placeId: "Eiw0MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
||||||
latitude: 34.2611486
|
latitude: 34.2611486
|
||||||
longitude: -118.5010287
|
longitude: -118.5010287
|
||||||
status: ASSIGNED
|
status: OPEN
|
||||||
workersNeeded: 2
|
workersNeeded: 2
|
||||||
filled: 1
|
filled: 1
|
||||||
}
|
}
|
||||||
@@ -1042,7 +1042,7 @@ mutation seedAll @transaction {
|
|||||||
placeId: "Eiw1MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
placeId: "Eiw1MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw"
|
||||||
latitude: 34.2611486
|
latitude: 34.2611486
|
||||||
longitude: -118.5010287
|
longitude: -118.5010287
|
||||||
status: ASSIGNED
|
status: OPEN
|
||||||
workersNeeded: 2
|
workersNeeded: 2
|
||||||
filled: 1
|
filled: 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
enum ShiftStatus {
|
enum ShiftStatus {
|
||||||
DRAFT
|
DRAFT
|
||||||
FILLED
|
FILLED
|
||||||
PENDING
|
|
||||||
ASSIGNED
|
ASSIGNED
|
||||||
CONFIRMED
|
|
||||||
OPEN
|
OPEN
|
||||||
IN_PROGRESS
|
IN_PROGRESS
|
||||||
COMPLETED
|
COMPLETED
|
||||||
|
|||||||
Reference in New Issue
Block a user