diff --git a/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/get_completed_shifts_by_business_id.dart b/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/get_completed_shifts_by_business_id.dart new file mode 100644 index 00000000..67bc9a40 --- /dev/null +++ b/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/get_completed_shifts_by_business_id.dart @@ -0,0 +1,268 @@ +part of 'generated.dart'; + +class GetCompletedShiftsByBusinessIdVariablesBuilder { + String businessId; + Timestamp dateFrom; + Timestamp dateTo; + Optional _offset = Optional.optional(nativeFromJson, nativeToJson); + Optional _limit = Optional.optional(nativeFromJson, nativeToJson); + + final FirebaseDataConnect _dataConnect; GetCompletedShiftsByBusinessIdVariablesBuilder offset(int? t) { + _offset.value = t; + return this; + } + GetCompletedShiftsByBusinessIdVariablesBuilder limit(int? t) { + _limit.value = t; + return this; + } + + GetCompletedShiftsByBusinessIdVariablesBuilder(this._dataConnect, {required this.businessId,required this.dateFrom,required this.dateTo,}); + Deserializer dataDeserializer = (dynamic json) => GetCompletedShiftsByBusinessIdData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (GetCompletedShiftsByBusinessIdVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return ref().execute(); + } + + QueryRef ref() { + GetCompletedShiftsByBusinessIdVariables vars= GetCompletedShiftsByBusinessIdVariables(businessId: businessId,dateFrom: dateFrom,dateTo: dateTo,offset: _offset,limit: _limit,); + return _dataConnect.query("getCompletedShiftsByBusinessId", dataDeserializer, varsSerializer, vars); + } +} + +@immutable +class GetCompletedShiftsByBusinessIdShifts { + final String id; + final Timestamp? date; + final Timestamp? startTime; + final Timestamp? endTime; + final double? hours; + final double? cost; + final int? workersNeeded; + final int? filled; + final Timestamp? createdAt; + final GetCompletedShiftsByBusinessIdShiftsOrder order; + GetCompletedShiftsByBusinessIdShifts.fromJson(dynamic json): + + id = nativeFromJson(json['id']), + date = json['date'] == null ? null : Timestamp.fromJson(json['date']), + startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']), + endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']), + hours = json['hours'] == null ? null : nativeFromJson(json['hours']), + cost = json['cost'] == null ? null : nativeFromJson(json['cost']), + workersNeeded = json['workersNeeded'] == null ? null : nativeFromJson(json['workersNeeded']), + filled = json['filled'] == null ? null : nativeFromJson(json['filled']), + createdAt = json['createdAt'] == null ? null : Timestamp.fromJson(json['createdAt']), + order = GetCompletedShiftsByBusinessIdShiftsOrder.fromJson(json['order']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final GetCompletedShiftsByBusinessIdShifts otherTyped = other as GetCompletedShiftsByBusinessIdShifts; + return id == otherTyped.id && + date == otherTyped.date && + startTime == otherTyped.startTime && + endTime == otherTyped.endTime && + hours == otherTyped.hours && + cost == otherTyped.cost && + workersNeeded == otherTyped.workersNeeded && + filled == otherTyped.filled && + createdAt == otherTyped.createdAt && + order == otherTyped.order; + + } + @override + int get hashCode => Object.hashAll([id.hashCode, date.hashCode, startTime.hashCode, endTime.hashCode, hours.hashCode, cost.hashCode, workersNeeded.hashCode, filled.hashCode, createdAt.hashCode, order.hashCode]); + + + Map toJson() { + Map json = {}; + json['id'] = nativeToJson(id); + if (date != null) { + json['date'] = date!.toJson(); + } + if (startTime != null) { + json['startTime'] = startTime!.toJson(); + } + if (endTime != null) { + json['endTime'] = endTime!.toJson(); + } + if (hours != null) { + json['hours'] = nativeToJson(hours); + } + if (cost != null) { + json['cost'] = nativeToJson(cost); + } + if (workersNeeded != null) { + json['workersNeeded'] = nativeToJson(workersNeeded); + } + if (filled != null) { + json['filled'] = nativeToJson(filled); + } + if (createdAt != null) { + json['createdAt'] = createdAt!.toJson(); + } + json['order'] = order.toJson(); + return json; + } + + GetCompletedShiftsByBusinessIdShifts({ + required this.id, + this.date, + this.startTime, + this.endTime, + this.hours, + this.cost, + this.workersNeeded, + this.filled, + this.createdAt, + required this.order, + }); +} + +@immutable +class GetCompletedShiftsByBusinessIdShiftsOrder { + final EnumValue status; + GetCompletedShiftsByBusinessIdShiftsOrder.fromJson(dynamic json): + + status = orderStatusDeserializer(json['status']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final GetCompletedShiftsByBusinessIdShiftsOrder otherTyped = other as GetCompletedShiftsByBusinessIdShiftsOrder; + return status == otherTyped.status; + + } + @override + int get hashCode => status.hashCode; + + + Map toJson() { + Map json = {}; + json['status'] = + orderStatusSerializer(status) + ; + return json; + } + + GetCompletedShiftsByBusinessIdShiftsOrder({ + required this.status, + }); +} + +@immutable +class GetCompletedShiftsByBusinessIdData { + final List shifts; + GetCompletedShiftsByBusinessIdData.fromJson(dynamic json): + + shifts = (json['shifts'] as List) + .map((e) => GetCompletedShiftsByBusinessIdShifts.fromJson(e)) + .toList(); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final GetCompletedShiftsByBusinessIdData otherTyped = other as GetCompletedShiftsByBusinessIdData; + return shifts == otherTyped.shifts; + + } + @override + int get hashCode => shifts.hashCode; + + + Map toJson() { + Map json = {}; + json['shifts'] = shifts.map((e) => e.toJson()).toList(); + return json; + } + + GetCompletedShiftsByBusinessIdData({ + required this.shifts, + }); +} + +@immutable +class GetCompletedShiftsByBusinessIdVariables { + final String businessId; + final Timestamp dateFrom; + final Timestamp dateTo; + late final Optionaloffset; + late final Optionallimit; + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + GetCompletedShiftsByBusinessIdVariables.fromJson(Map json): + + businessId = nativeFromJson(json['businessId']), + dateFrom = Timestamp.fromJson(json['dateFrom']), + dateTo = Timestamp.fromJson(json['dateTo']) { + + + + + + offset = Optional.optional(nativeFromJson, nativeToJson); + offset.value = json['offset'] == null ? null : nativeFromJson(json['offset']); + + + limit = Optional.optional(nativeFromJson, nativeToJson); + limit.value = json['limit'] == null ? null : nativeFromJson(json['limit']); + + } + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final GetCompletedShiftsByBusinessIdVariables otherTyped = other as GetCompletedShiftsByBusinessIdVariables; + return businessId == otherTyped.businessId && + dateFrom == otherTyped.dateFrom && + dateTo == otherTyped.dateTo && + offset == otherTyped.offset && + limit == otherTyped.limit; + + } + @override + int get hashCode => Object.hashAll([businessId.hashCode, dateFrom.hashCode, dateTo.hashCode, offset.hashCode, limit.hashCode]); + + + Map toJson() { + Map json = {}; + json['businessId'] = nativeToJson(businessId); + json['dateFrom'] = dateFrom.toJson(); + json['dateTo'] = dateTo.toJson(); + if(offset.state == OptionalState.set) { + json['offset'] = offset.toJson(); + } + if(limit.state == OptionalState.set) { + json['limit'] = limit.toJson(); + } + return json; + } + + GetCompletedShiftsByBusinessIdVariables({ + required this.businessId, + required this.dateFrom, + required this.dateTo, + required this.offset, + required this.limit, + }); +} + diff --git a/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_shift_roles_by_business_and_date_range.dart b/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_shift_roles_by_business_and_date_range.dart index f0aca6be..741c67d5 100644 --- a/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_shift_roles_by_business_and_date_range.dart +++ b/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_shift_roles_by_business_and_date_range.dart @@ -6,6 +6,7 @@ class ListShiftRolesByBusinessAndDateRangeVariablesBuilder { Timestamp end; Optional _offset = Optional.optional(nativeFromJson, nativeToJson); Optional _limit = Optional.optional(nativeFromJson, nativeToJson); + Optional _status = Optional.optional((data) => ShiftStatus.values.byName(data), enumSerializer); final FirebaseDataConnect _dataConnect; ListShiftRolesByBusinessAndDateRangeVariablesBuilder offset(int? t) { _offset.value = t; @@ -15,6 +16,10 @@ class ListShiftRolesByBusinessAndDateRangeVariablesBuilder { _limit.value = t; return this; } + ListShiftRolesByBusinessAndDateRangeVariablesBuilder status(ShiftStatus? t) { + _status.value = t; + return this; + } ListShiftRolesByBusinessAndDateRangeVariablesBuilder(this._dataConnect, {required this.businessId,required this.start,required this.end,}); Deserializer dataDeserializer = (dynamic json) => ListShiftRolesByBusinessAndDateRangeData.fromJson(jsonDecode(json)); @@ -24,7 +29,7 @@ class ListShiftRolesByBusinessAndDateRangeVariablesBuilder { } QueryRef ref() { - ListShiftRolesByBusinessAndDateRangeVariables vars= ListShiftRolesByBusinessAndDateRangeVariables(businessId: businessId,start: start,end: end,offset: _offset,limit: _limit,); + ListShiftRolesByBusinessAndDateRangeVariables vars= ListShiftRolesByBusinessAndDateRangeVariables(businessId: businessId,start: start,end: end,offset: _offset,limit: _limit,status: _status,); return _dataConnect.query("listShiftRolesByBusinessAndDateRange", dataDeserializer, varsSerializer, vars); } } @@ -308,6 +313,7 @@ class ListShiftRolesByBusinessAndDateRangeVariables { final Timestamp end; late final Optionaloffset; late final Optionallimit; + late final Optionalstatus; @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') ListShiftRolesByBusinessAndDateRangeVariables.fromJson(Map json): @@ -326,6 +332,10 @@ class ListShiftRolesByBusinessAndDateRangeVariables { limit = Optional.optional(nativeFromJson, nativeToJson); limit.value = json['limit'] == null ? null : nativeFromJson(json['limit']); + + status = Optional.optional((data) => ShiftStatus.values.byName(data), enumSerializer); + status.value = json['status'] == null ? null : ShiftStatus.values.byName(json['status']); + } @override bool operator ==(Object other) { @@ -341,11 +351,12 @@ class ListShiftRolesByBusinessAndDateRangeVariables { start == otherTyped.start && end == otherTyped.end && offset == otherTyped.offset && - limit == otherTyped.limit; + limit == otherTyped.limit && + status == otherTyped.status; } @override - int get hashCode => Object.hashAll([businessId.hashCode, start.hashCode, end.hashCode, offset.hashCode, limit.hashCode]); + int get hashCode => Object.hashAll([businessId.hashCode, start.hashCode, end.hashCode, offset.hashCode, limit.hashCode, status.hashCode]); Map toJson() { @@ -359,6 +370,9 @@ class ListShiftRolesByBusinessAndDateRangeVariables { if(limit.state == OptionalState.set) { json['limit'] = limit.toJson(); } + if(status.state == OptionalState.set) { + json['status'] = status.toJson(); + } return json; } @@ -368,6 +382,7 @@ class ListShiftRolesByBusinessAndDateRangeVariables { required this.end, required this.offset, required this.limit, + required this.status, }); } diff --git a/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_staffs_applications_by_business_for_day.dart b/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_staffs_applications_by_business_for_day.dart new file mode 100644 index 00000000..7c4ed250 --- /dev/null +++ b/apps/mobile/packages/data_connect/lib/src/dataconnect_generated/list_staffs_applications_by_business_for_day.dart @@ -0,0 +1,407 @@ +part of 'generated.dart'; + +class ListStaffsApplicationsByBusinessForDayVariablesBuilder { + String businessId; + Timestamp dayStart; + Timestamp dayEnd; + Optional _offset = Optional.optional(nativeFromJson, nativeToJson); + Optional _limit = Optional.optional(nativeFromJson, nativeToJson); + + final FirebaseDataConnect _dataConnect; ListStaffsApplicationsByBusinessForDayVariablesBuilder offset(int? t) { + _offset.value = t; + return this; + } + ListStaffsApplicationsByBusinessForDayVariablesBuilder limit(int? t) { + _limit.value = t; + return this; + } + + ListStaffsApplicationsByBusinessForDayVariablesBuilder(this._dataConnect, {required this.businessId,required this.dayStart,required this.dayEnd,}); + Deserializer dataDeserializer = (dynamic json) => ListStaffsApplicationsByBusinessForDayData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (ListStaffsApplicationsByBusinessForDayVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return ref().execute(); + } + + QueryRef ref() { + ListStaffsApplicationsByBusinessForDayVariables vars= ListStaffsApplicationsByBusinessForDayVariables(businessId: businessId,dayStart: dayStart,dayEnd: dayEnd,offset: _offset,limit: _limit,); + return _dataConnect.query("listStaffsApplicationsByBusinessForDay", dataDeserializer, varsSerializer, vars); + } +} + +@immutable +class ListStaffsApplicationsByBusinessForDayApplications { + final String id; + final String shiftId; + final String roleId; + final Timestamp? checkInTime; + final Timestamp? checkOutTime; + final Timestamp? appliedAt; + final EnumValue status; + final ListStaffsApplicationsByBusinessForDayApplicationsShiftRole shiftRole; + final ListStaffsApplicationsByBusinessForDayApplicationsStaff staff; + ListStaffsApplicationsByBusinessForDayApplications.fromJson(dynamic json): + + id = nativeFromJson(json['id']), + shiftId = nativeFromJson(json['shiftId']), + roleId = nativeFromJson(json['roleId']), + checkInTime = json['checkInTime'] == null ? null : Timestamp.fromJson(json['checkInTime']), + checkOutTime = json['checkOutTime'] == null ? null : Timestamp.fromJson(json['checkOutTime']), + appliedAt = json['appliedAt'] == null ? null : Timestamp.fromJson(json['appliedAt']), + status = applicationStatusDeserializer(json['status']), + shiftRole = ListStaffsApplicationsByBusinessForDayApplicationsShiftRole.fromJson(json['shiftRole']), + staff = ListStaffsApplicationsByBusinessForDayApplicationsStaff.fromJson(json['staff']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayApplications otherTyped = other as ListStaffsApplicationsByBusinessForDayApplications; + return id == otherTyped.id && + shiftId == otherTyped.shiftId && + roleId == otherTyped.roleId && + checkInTime == otherTyped.checkInTime && + checkOutTime == otherTyped.checkOutTime && + appliedAt == otherTyped.appliedAt && + status == otherTyped.status && + shiftRole == otherTyped.shiftRole && + staff == otherTyped.staff; + + } + @override + int get hashCode => Object.hashAll([id.hashCode, shiftId.hashCode, roleId.hashCode, checkInTime.hashCode, checkOutTime.hashCode, appliedAt.hashCode, status.hashCode, shiftRole.hashCode, staff.hashCode]); + + + Map toJson() { + Map json = {}; + json['id'] = nativeToJson(id); + json['shiftId'] = nativeToJson(shiftId); + json['roleId'] = nativeToJson(roleId); + if (checkInTime != null) { + json['checkInTime'] = checkInTime!.toJson(); + } + if (checkOutTime != null) { + json['checkOutTime'] = checkOutTime!.toJson(); + } + if (appliedAt != null) { + json['appliedAt'] = appliedAt!.toJson(); + } + json['status'] = + applicationStatusSerializer(status) + ; + json['shiftRole'] = shiftRole.toJson(); + json['staff'] = staff.toJson(); + return json; + } + + ListStaffsApplicationsByBusinessForDayApplications({ + required this.id, + required this.shiftId, + required this.roleId, + this.checkInTime, + this.checkOutTime, + this.appliedAt, + required this.status, + required this.shiftRole, + required this.staff, + }); +} + +@immutable +class ListStaffsApplicationsByBusinessForDayApplicationsShiftRole { + final ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift shift; + final int count; + final int? assigned; + final ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole role; + ListStaffsApplicationsByBusinessForDayApplicationsShiftRole.fromJson(dynamic json): + + shift = ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift.fromJson(json['shift']), + count = nativeFromJson(json['count']), + assigned = json['assigned'] == null ? null : nativeFromJson(json['assigned']), + role = ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole.fromJson(json['role']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayApplicationsShiftRole otherTyped = other as ListStaffsApplicationsByBusinessForDayApplicationsShiftRole; + return shift == otherTyped.shift && + count == otherTyped.count && + assigned == otherTyped.assigned && + role == otherTyped.role; + + } + @override + int get hashCode => Object.hashAll([shift.hashCode, count.hashCode, assigned.hashCode, role.hashCode]); + + + Map toJson() { + Map json = {}; + json['shift'] = shift.toJson(); + json['count'] = nativeToJson(count); + if (assigned != null) { + json['assigned'] = nativeToJson(assigned); + } + json['role'] = role.toJson(); + return json; + } + + ListStaffsApplicationsByBusinessForDayApplicationsShiftRole({ + required this.shift, + required this.count, + this.assigned, + required this.role, + }); +} + +@immutable +class ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift { + final String? location; + final double? cost; + ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift.fromJson(dynamic json): + + location = json['location'] == null ? null : nativeFromJson(json['location']), + cost = json['cost'] == null ? null : nativeFromJson(json['cost']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift otherTyped = other as ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift; + return location == otherTyped.location && + cost == otherTyped.cost; + + } + @override + int get hashCode => Object.hashAll([location.hashCode, cost.hashCode]); + + + Map toJson() { + Map json = {}; + if (location != null) { + json['location'] = nativeToJson(location); + } + if (cost != null) { + json['cost'] = nativeToJson(cost); + } + return json; + } + + ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleShift({ + this.location, + this.cost, + }); +} + +@immutable +class ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole { + final String name; + ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole.fromJson(dynamic json): + + name = nativeFromJson(json['name']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole otherTyped = other as ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole; + return name == otherTyped.name; + + } + @override + int get hashCode => name.hashCode; + + + Map toJson() { + Map json = {}; + json['name'] = nativeToJson(name); + return json; + } + + ListStaffsApplicationsByBusinessForDayApplicationsShiftRoleRole({ + required this.name, + }); +} + +@immutable +class ListStaffsApplicationsByBusinessForDayApplicationsStaff { + final String id; + final String fullName; + final String? email; + final String? phone; + final String? photoUrl; + ListStaffsApplicationsByBusinessForDayApplicationsStaff.fromJson(dynamic json): + + id = nativeFromJson(json['id']), + fullName = nativeFromJson(json['fullName']), + email = json['email'] == null ? null : nativeFromJson(json['email']), + phone = json['phone'] == null ? null : nativeFromJson(json['phone']), + photoUrl = json['photoUrl'] == null ? null : nativeFromJson(json['photoUrl']); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayApplicationsStaff otherTyped = other as ListStaffsApplicationsByBusinessForDayApplicationsStaff; + return id == otherTyped.id && + fullName == otherTyped.fullName && + email == otherTyped.email && + phone == otherTyped.phone && + photoUrl == otherTyped.photoUrl; + + } + @override + int get hashCode => Object.hashAll([id.hashCode, fullName.hashCode, email.hashCode, phone.hashCode, photoUrl.hashCode]); + + + Map toJson() { + Map json = {}; + json['id'] = nativeToJson(id); + json['fullName'] = nativeToJson(fullName); + if (email != null) { + json['email'] = nativeToJson(email); + } + if (phone != null) { + json['phone'] = nativeToJson(phone); + } + if (photoUrl != null) { + json['photoUrl'] = nativeToJson(photoUrl); + } + return json; + } + + ListStaffsApplicationsByBusinessForDayApplicationsStaff({ + required this.id, + required this.fullName, + this.email, + this.phone, + this.photoUrl, + }); +} + +@immutable +class ListStaffsApplicationsByBusinessForDayData { + final List applications; + ListStaffsApplicationsByBusinessForDayData.fromJson(dynamic json): + + applications = (json['applications'] as List) + .map((e) => ListStaffsApplicationsByBusinessForDayApplications.fromJson(e)) + .toList(); + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayData otherTyped = other as ListStaffsApplicationsByBusinessForDayData; + return applications == otherTyped.applications; + + } + @override + int get hashCode => applications.hashCode; + + + Map toJson() { + Map json = {}; + json['applications'] = applications.map((e) => e.toJson()).toList(); + return json; + } + + ListStaffsApplicationsByBusinessForDayData({ + required this.applications, + }); +} + +@immutable +class ListStaffsApplicationsByBusinessForDayVariables { + final String businessId; + final Timestamp dayStart; + final Timestamp dayEnd; + late final Optionaloffset; + late final Optionallimit; + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + ListStaffsApplicationsByBusinessForDayVariables.fromJson(Map json): + + businessId = nativeFromJson(json['businessId']), + dayStart = Timestamp.fromJson(json['dayStart']), + dayEnd = Timestamp.fromJson(json['dayEnd']) { + + + + + + offset = Optional.optional(nativeFromJson, nativeToJson); + offset.value = json['offset'] == null ? null : nativeFromJson(json['offset']); + + + limit = Optional.optional(nativeFromJson, nativeToJson); + limit.value = json['limit'] == null ? null : nativeFromJson(json['limit']); + + } + @override + bool operator ==(Object other) { + if(identical(this, other)) { + return true; + } + if(other.runtimeType != runtimeType) { + return false; + } + + final ListStaffsApplicationsByBusinessForDayVariables otherTyped = other as ListStaffsApplicationsByBusinessForDayVariables; + return businessId == otherTyped.businessId && + dayStart == otherTyped.dayStart && + dayEnd == otherTyped.dayEnd && + offset == otherTyped.offset && + limit == otherTyped.limit; + + } + @override + int get hashCode => Object.hashAll([businessId.hashCode, dayStart.hashCode, dayEnd.hashCode, offset.hashCode, limit.hashCode]); + + + Map toJson() { + Map json = {}; + json['businessId'] = nativeToJson(businessId); + json['dayStart'] = dayStart.toJson(); + json['dayEnd'] = dayEnd.toJson(); + if(offset.state == OptionalState.set) { + json['offset'] = offset.toJson(); + } + if(limit.state == OptionalState.set) { + json['limit'] = limit.toJson(); + } + return json; + } + + ListStaffsApplicationsByBusinessForDayVariables({ + required this.businessId, + required this.dayStart, + required this.dayEnd, + required this.offset, + required this.limit, + }); +} + diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart index 053ec29d..d42bda3f 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart @@ -22,22 +22,7 @@ class InvoiceHistorySection extends StatelessWidget { t.client_billing.invoice_history, style: UiTypography.title2b.textPrimary, ), - GestureDetector( - onTap: () {}, - child: Row( - children: [ - Text( - t.client_billing.view_all, - style: UiTypography.footnote2b.textPrimary, - ), - const Icon( - UiIcons.chevronRight, - size: 16, - color: UiColors.primary, - ), - ], - ), - ), + const SizedBox.shrink(), ], ), const SizedBox(height: UiConstants.space2), @@ -117,8 +102,7 @@ class _InvoiceItem extends StatelessWidget { _StatusBadge(status: invoice.status), ], ), - const SizedBox(width: UiConstants.space2), - const Icon(UiIcons.download, size: 16, color: UiColors.iconSecondary), + const SizedBox.shrink(), ], ), ); diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/payment_method_card.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/payment_method_card.dart index 40715687..6c846212 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/payment_method_card.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/payment_method_card.dart @@ -69,29 +69,13 @@ class _PaymentMethodCardState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - t.client_billing.payment_method, - style: UiTypography.title2b.textPrimary, - ), - GestureDetector( - onTap: () {}, - child: Row( - children: [ - const Icon( - UiIcons.add, - size: 14, - color: UiColors.primary, - ), - const SizedBox(width: 4), - Text( - t.client_billing.add_payment, - style: UiTypography.footnote2b.textPrimary, - ), - ], - ), - ), - ], + Text( + t.client_billing.payment_method, + style: UiTypography.title2b.textPrimary, ), + const SizedBox.shrink(), + ], + ), if (account != null) ...[ const SizedBox(height: UiConstants.space3), Container( diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/savings_card.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/savings_card.dart index 18ea1dfd..cc455c67 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/savings_card.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/savings_card.dart @@ -50,25 +50,7 @@ class SavingsCard extends StatelessWidget { style: UiTypography.footnote2r.textSecondary, ), const SizedBox(height: UiConstants.space2), - SizedBox( - height: 28, - child: ElevatedButton( - onPressed: () {}, - style: ElevatedButton.styleFrom( - backgroundColor: UiColors.primary, - foregroundColor: UiColors.white, - elevation: 0, - padding: const EdgeInsets.symmetric( - horizontal: UiConstants.space3, - ), - shape: RoundedRectangleBorder( - borderRadius: UiConstants.radiusMd, - ), - textStyle: UiTypography.footnote2b, - ), - child: Text(t.client_billing.view_details), - ), - ), + const SizedBox.shrink(), ], ), ), diff --git a/apps/mobile/packages/features/client/client_coverage/lib/src/coverage_module.dart b/apps/mobile/packages/features/client/client_coverage/lib/src/coverage_module.dart index 5a155704..19e3bd5a 100644 --- a/apps/mobile/packages/features/client/client_coverage/lib/src/coverage_module.dart +++ b/apps/mobile/packages/features/client/client_coverage/lib/src/coverage_module.dart @@ -1,4 +1,5 @@ import 'package:flutter_modular/flutter_modular.dart'; +import 'package:krow_data_connect/krow_data_connect.dart'; import 'data/repositories_impl/coverage_repository_impl.dart'; import 'domain/repositories/coverage_repository.dart'; import 'domain/usecases/get_coverage_stats_usecase.dart'; @@ -11,7 +12,9 @@ class CoverageModule extends Module { @override void binds(Injector i) { // Repositories - i.addSingleton(CoverageRepositoryImpl.new); + i.addSingleton( + () => CoverageRepositoryImpl(dataConnect: ExampleConnector.instance), + ); // Use Cases i.addSingleton(GetShiftsForDateUseCase.new); diff --git a/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart b/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart index fdee9b3f..fa29d536 100644 --- a/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart +++ b/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart @@ -1,3 +1,5 @@ +import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc; +import 'package:krow_data_connect/krow_data_connect.dart' as dc; import '../../domain/repositories/coverage_repository.dart'; import '../../domain/ui_entities/coverage_entities.dart'; @@ -13,82 +15,58 @@ import '../../domain/ui_entities/coverage_entities.dart'; /// - Returns domain entities from `domain/ui_entities`. class CoverageRepositoryImpl implements CoverageRepository { /// Creates a [CoverageRepositoryImpl]. - CoverageRepositoryImpl(); + CoverageRepositoryImpl({required dc.ExampleConnector dataConnect}) + : _dataConnect = dataConnect; + + final dc.ExampleConnector _dataConnect; /// Fetches shifts for a specific date. @override Future> getShiftsForDate({required DateTime date}) async { - // Simulate network delay - await Future.delayed(const Duration(milliseconds: 500)); - - // Mock data - in production, this would come from data_connect - final DateTime today = DateTime.now(); - final bool isToday = date.year == today.year && - date.month == today.month && - date.day == today.day; - - if (!isToday) { - // Return empty list for non-today dates + final String? businessId = + dc.ClientSessionStore.instance.session?.business?.id; + print('Coverage: now=${DateTime.now().toIso8601String()}'); + if (businessId == null || businessId.isEmpty) { + print('Coverage: missing businessId for date=${date.toIso8601String()}'); return []; } - return [ - CoverageShift( - id: '1', - title: 'Banquet Server', - location: 'Grand Ballroom', - startTime: '16:00', - workersNeeded: 10, - date: date, - workers: const [ - CoverageWorker( - name: 'Sarah Wilson', - status: 'confirmed', - checkInTime: '15:55', - ), - CoverageWorker( - name: 'Mike Ross', - status: 'confirmed', - checkInTime: '16:00', - ), - CoverageWorker( - name: 'Jane Doe', - status: 'confirmed', - checkInTime: null, - ), - CoverageWorker( - name: 'John Smith', - status: 'late', - checkInTime: null, - ), - ], - ), - CoverageShift( - id: '2', - title: 'Bartender', - location: 'Lobby Bar', - startTime: '17:00', - workersNeeded: 4, - date: date, - workers: const [ - CoverageWorker( - name: 'Emily Blunt', - status: 'confirmed', - checkInTime: '16:45', - ), - CoverageWorker( - name: 'Chris Evans', - status: 'confirmed', - checkInTime: '16:50', - ), - CoverageWorker( - name: 'Tom Holland', - status: 'confirmed', - checkInTime: null, - ), - ], - ), - ]; + final DateTime start = DateTime(date.year, date.month, date.day); + final DateTime end = + DateTime(date.year, date.month, date.day, 23, 59, 59, 999); + print( + 'Coverage: request businessId=$businessId dayStart=${start.toIso8601String()} dayEnd=${end.toIso8601String()}', + ); + final fdc.QueryResult< + dc.ListShiftRolesByBusinessAndDateRangeData, + dc.ListShiftRolesByBusinessAndDateRangeVariables> shiftRolesResult = + await _dataConnect + .listShiftRolesByBusinessAndDateRange( + businessId: businessId, + start: _toTimestamp(start), + end: _toTimestamp(end), + ) + .execute(); + + final fdc.QueryResult< + dc.ListStaffsApplicationsByBusinessForDayData, + dc.ListStaffsApplicationsByBusinessForDayVariables> applicationsResult = + await _dataConnect + .listStaffsApplicationsByBusinessForDay( + businessId: businessId, + dayStart: _toTimestamp(start), + dayEnd: _toTimestamp(end), + ) + .execute(); + print( + 'Coverage: ${date.toIso8601String()} staffsApplications=${applicationsResult.data.applications.length}', + ); + + return _mapCoverageShifts( + shiftRolesResult.data.shiftRoles, + applicationsResult.data.applications, + date, + ); } /// Fetches coverage statistics for a specific date. @@ -120,4 +98,128 @@ class CoverageRepositoryImpl implements CoverageRepository { late: late, ); } + + fdc.Timestamp _toTimestamp(DateTime dateTime) { + final int seconds = dateTime.millisecondsSinceEpoch ~/ 1000; + final int nanoseconds = + (dateTime.millisecondsSinceEpoch % 1000) * 1000000; + return fdc.Timestamp(nanoseconds, seconds); + } + + List _mapCoverageShifts( + List shiftRoles, + List applications, + DateTime date, + ) { + if (shiftRoles.isEmpty && applications.isEmpty) { + return []; + } + + final Map groups = {}; + for (final dc.ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole + in shiftRoles) { + final String key = '${shiftRole.shiftId}:${shiftRole.roleId}'; + groups[key] = _CoverageGroup( + shiftId: shiftRole.shiftId, + roleId: shiftRole.roleId, + title: shiftRole.role.name, + location: shiftRole.shift.location ?? '', + startTime: _formatTime(shiftRole.startTime) ?? '00:00', + workersNeeded: shiftRole.count, + date: shiftRole.shift.date?.toDateTime() ?? date, + workers: [], + ); + } + + for (final dc.ListStaffsApplicationsByBusinessForDayApplications app + in applications) { + final String key = '${app.shiftId}:${app.roleId}'; + final _CoverageGroup existing = groups[key] ?? + _CoverageGroup( + shiftId: app.shiftId, + roleId: app.roleId, + title: app.shiftRole.role.name, + location: app.shiftRole.shift.location ?? '', + startTime: '00:00', + workersNeeded: 0, + date: date, + workers: [], + ); + + existing.workers.add( + CoverageWorker( + name: app.staff.fullName, + status: _mapWorkerStatus(app.status), + checkInTime: _formatTime(app.checkInTime), + ), + ); + groups[key] = existing; + } + + return groups.values + .map( + (_CoverageGroup group) => CoverageShift( + id: '${group.shiftId}:${group.roleId}', + title: group.title, + location: group.location, + startTime: group.startTime, + workersNeeded: group.workersNeeded, + date: group.date, + workers: group.workers, + ), + ) + .toList(); + } + + String _mapWorkerStatus( + dc.EnumValue status, + ) { + if (status is dc.Known) { + switch (status.value) { + case dc.ApplicationStatus.LATE: + return 'late'; + case dc.ApplicationStatus.CHECKED_IN: + case dc.ApplicationStatus.CHECKED_OUT: + case dc.ApplicationStatus.ACCEPTED: + case dc.ApplicationStatus.CONFIRMED: + case dc.ApplicationStatus.PENDING: + case dc.ApplicationStatus.REJECTED: + case dc.ApplicationStatus.NO_SHOW: + return 'confirmed'; + } + } + return 'confirmed'; + } + + String? _formatTime(fdc.Timestamp? timestamp) { + if (timestamp == null) { + return null; + } + final DateTime date = timestamp.toDateTime(); + final String hour = date.hour.toString().padLeft(2, '0'); + final String minute = date.minute.toString().padLeft(2, '0'); + return '$hour:$minute'; + } +} + +class _CoverageGroup { + _CoverageGroup({ + required this.shiftId, + required this.roleId, + required this.title, + required this.location, + required this.startTime, + required this.workersNeeded, + required this.date, + required this.workers, + }); + + final String shiftId; + final String roleId; + final String title; + final String location; + final String startTime; + final int workersNeeded; + final DateTime date; + final List workers; } diff --git a/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart b/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart index f1f1f5cb..6c9513bb 100644 --- a/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart +++ b/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart @@ -53,7 +53,7 @@ class CoverageHeader extends StatelessWidget { gradient: LinearGradient( colors: [ UiColors.primary, - UiColors.accent, + UiColors.primary, ], begin: Alignment.topLeft, end: Alignment.bottomRight, diff --git a/apps/mobile/packages/features/client/home/lib/src/data/repositories_impl/home_repository_impl.dart b/apps/mobile/packages/features/client/home/lib/src/data/repositories_impl/home_repository_impl.dart index 0239e73a..19b08b29 100644 --- a/apps/mobile/packages/features/client/home/lib/src/data/repositories_impl/home_repository_impl.dart +++ b/apps/mobile/packages/features/client/home/lib/src/data/repositories_impl/home_repository_impl.dart @@ -17,8 +17,95 @@ class HomeRepositoryImpl implements HomeRepositoryInterface { HomeRepositoryImpl(this._mock, this._dataConnect); @override - Future getDashboardData() { - return _mock.getDashboardData(); + Future getDashboardData() async { + final String? businessId = ClientSessionStore.instance.session?.business?.id; + if (businessId == null || businessId.isEmpty) { + return const HomeDashboardData( + weeklySpending: 0, + next7DaysSpending: 0, + weeklyShifts: 0, + next7DaysScheduled: 0, + totalNeeded: 0, + totalFilled: 0, + ); + } + + final DateTime now = DateTime.now(); + final int daysFromMonday = now.weekday - DateTime.monday; + final DateTime monday = + DateTime(now.year, now.month, now.day).subtract(Duration(days: daysFromMonday)); + final DateTime weekRangeStart = DateTime(monday.year, monday.month, monday.day); + final DateTime weekRangeEnd = + DateTime(monday.year, monday.month, monday.day + 13, 23, 59, 59, 999); + final fdc.QueryResult< + GetCompletedShiftsByBusinessIdData, + GetCompletedShiftsByBusinessIdVariables> completedResult = + await _dataConnect + .getCompletedShiftsByBusinessId( + businessId: businessId, + dateFrom: _toTimestamp(weekRangeStart), + dateTo: _toTimestamp(weekRangeEnd), + ) + .execute(); + print( + 'Home spending: businessId=$businessId dateFrom=${weekRangeStart.toIso8601String()} ' + 'dateTo=${weekRangeEnd.toIso8601String()} shifts=${completedResult.data.shifts.length}', + ); + + double weeklySpending = 0.0; + double next7DaysSpending = 0.0; + int weeklyShifts = 0; + int next7DaysScheduled = 0; + for (final GetCompletedShiftsByBusinessIdShifts shift + in completedResult.data.shifts) { + final DateTime? shiftDate = shift.date?.toDateTime(); + if (shiftDate == null) { + continue; + } + final int offset = shiftDate.difference(weekRangeStart).inDays; + if (offset < 0 || offset > 13) { + continue; + } + final double cost = shift.cost ?? 0.0; + if (offset <= 6) { + weeklySpending += cost; + weeklyShifts += 1; + } else { + next7DaysSpending += cost; + next7DaysScheduled += 1; + } + } + + final DateTime start = DateTime(now.year, now.month, now.day); + final DateTime end = DateTime(now.year, now.month, now.day, 23, 59, 59, 999); + + final fdc.QueryResult< + ListShiftRolesByBusinessAndDateRangeData, + ListShiftRolesByBusinessAndDateRangeVariables> result = + await _dataConnect + .listShiftRolesByBusinessAndDateRange( + businessId: businessId, + start: _toTimestamp(start), + end: _toTimestamp(end), + ) + .execute(); + + int totalNeeded = 0; + int totalFilled = 0; + for (final ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole + in result.data.shiftRoles) { + totalNeeded += shiftRole.count; + totalFilled += shiftRole.assigned ?? 0; + } + + return HomeDashboardData( + weeklySpending: weeklySpending, + next7DaysSpending: next7DaysSpending, + weeklyShifts: weeklyShifts, + next7DaysScheduled: next7DaysScheduled, + totalNeeded: totalNeeded, + totalFilled: totalFilled, + ); } @override diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/blocs/client_home_state.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/blocs/client_home_state.dart index cee3337e..f92cc85d 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/blocs/client_home_state.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/blocs/client_home_state.dart @@ -21,10 +21,16 @@ class ClientHomeState extends Equatable { this.widgetOrder = const [ 'actions', 'reorder', + 'coverage', + 'spending', + 'liveActivity', ], this.widgetVisibility = const { 'actions': true, 'reorder': true, + 'coverage': true, + 'spending': true, + 'liveActivity': true, }, this.isEditMode = false, this.errorMessage, diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart index d5d13ec8..83a333d7 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart @@ -94,7 +94,9 @@ class DashboardWidgetBuilder extends StatelessWidget { : 0, ); case 'liveActivity': - return LiveActivityWidget(onViewAllPressed: () {}); + return LiveActivityWidget( + onViewAllPressed: () => Modular.to.navigate('/client-main/coverage/'), + ); default: return const SizedBox.shrink(); } diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart index 47bbcfb9..1c91a655 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart @@ -1,44 +1,107 @@ import 'package:core_localization/core_localization.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; +import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc; +import 'package:krow_data_connect/krow_data_connect.dart' as dc; import 'coverage_dashboard.dart'; /// A widget that displays live activity information. -class LiveActivityWidget extends StatelessWidget { +class LiveActivityWidget extends StatefulWidget { /// Callback when "View all" is pressed. final VoidCallback onViewAllPressed; /// Creates a [LiveActivityWidget]. const LiveActivityWidget({super.key, required this.onViewAllPressed}); + @override + State createState() => _LiveActivityWidgetState(); +} + +class _LiveActivityWidgetState extends State { + late final Future<_LiveActivityData> _liveActivityFuture = + _loadLiveActivity(); + + Future<_LiveActivityData> _loadLiveActivity() async { + final String? businessId = + dc.ClientSessionStore.instance.session?.business?.id; + if (businessId == null || businessId.isEmpty) { + return _LiveActivityData.empty(); + } + + final DateTime now = DateTime.now(); + final DateTime start = DateTime(now.year, now.month, now.day); + final DateTime end = DateTime(now.year, now.month, now.day, 23, 59, 59, 999); + final fdc.QueryResult result = + await dc.ExampleConnector.instance + .listStaffsApplicationsByBusinessForDay( + businessId: businessId, + dayStart: _toTimestamp(start), + dayEnd: _toTimestamp(end), + ) + .execute(); + + if (result.data.applications.isEmpty) { + return _LiveActivityData.empty(); + } + + final Map aggregates = + {}; + for (final dc.ListStaffsApplicationsByBusinessForDayApplications app + in result.data.applications) { + final String key = '${app.shiftId}:${app.roleId}'; + final _LiveShiftAggregate aggregate = aggregates[key] ?? + _LiveShiftAggregate( + workersNeeded: app.shiftRole.count, + assigned: app.shiftRole.assigned ?? 0, + cost: app.shiftRole.shift.cost ?? 0, + ); + aggregates[key] = aggregate; + } + + int totalNeeded = 0; + int totalAssigned = 0; + double totalCost = 0; + for (final _LiveShiftAggregate aggregate in aggregates.values) { + totalNeeded += aggregate.workersNeeded; + totalAssigned += aggregate.assigned; + totalCost += aggregate.cost; + } + + int lateCount = 0; + int checkedInCount = 0; + for (final dc.ListStaffsApplicationsByBusinessForDayApplications app + in result.data.applications) { + if (app.checkInTime != null) { + checkedInCount += 1; + } + if (app.status is dc.Known && + (app.status as dc.Known).value == + dc.ApplicationStatus.LATE) { + lateCount += 1; + } + } + + return _LiveActivityData( + totalNeeded: totalNeeded, + totalAssigned: totalAssigned, + totalCost: totalCost, + checkedInCount: checkedInCount, + lateCount: lateCount, + ); + } + + fdc.Timestamp _toTimestamp(DateTime dateTime) { + final int seconds = dateTime.millisecondsSinceEpoch ~/ 1000; + final int nanoseconds = + (dateTime.millisecondsSinceEpoch % 1000) * 1000000; + return fdc.Timestamp(nanoseconds, seconds); + } + @override Widget build(BuildContext context) { final TranslationsClientHomeEn i18n = t.client_home; - // Mock data - final List> shifts = >[ - { - 'workersNeeded': 5, - 'filled': 4, - 'hourlyRate': 20.0, - 'status': 'OPEN', - 'date': DateTime.now().toIso8601String().split('T')[0], - }, - { - 'workersNeeded': 5, - 'filled': 5, - 'hourlyRate': 22.0, - 'status': 'FILLED', - 'date': DateTime.now().toIso8601String().split('T')[0], - }, - ]; - final List> applications = >[ - {'status': 'CONFIRMED', 'checkInTime': '09:00'}, - {'status': 'CONFIRMED', 'checkInTime': '09:05'}, - {'status': 'CONFIRMED'}, - {'status': 'LATE'}, - ]; - return Column( children: [ Row( @@ -51,7 +114,7 @@ class LiveActivityWidget extends StatelessWidget { ), ), GestureDetector( - onTap: onViewAllPressed, + onTap: widget.onViewAllPressed, child: Text( i18n.dashboard.view_all, style: UiTypography.footnote1m.copyWith( @@ -62,8 +125,82 @@ class LiveActivityWidget extends StatelessWidget { ], ), const SizedBox(height: UiConstants.space2), - CoverageDashboard(shifts: shifts, applications: applications), + FutureBuilder<_LiveActivityData>( + future: _liveActivityFuture, + builder: (BuildContext context, + AsyncSnapshot<_LiveActivityData> snapshot) { + final _LiveActivityData data = + snapshot.data ?? _LiveActivityData.empty(); + final List> shifts = + >[ + { + 'workersNeeded': data.totalNeeded, + 'filled': data.totalAssigned, + 'hourlyRate': data.totalAssigned == 0 + ? 0.0 + : data.totalCost / data.totalAssigned, + 'status': 'OPEN', + 'date': DateTime.now().toIso8601String().split('T')[0], + }, + ]; + final List> applications = + >[]; + for (int i = 0; i < data.checkedInCount; i += 1) { + applications.add( + { + 'status': 'CONFIRMED', + 'checkInTime': '09:00', + }, + ); + } + for (int i = 0; i < data.lateCount; i += 1) { + applications.add({'status': 'LATE'}); + } + return CoverageDashboard( + shifts: shifts, + applications: applications, + ); + }, + ), ], ); } } + +class _LiveActivityData { + const _LiveActivityData({ + required this.totalNeeded, + required this.totalAssigned, + required this.totalCost, + required this.checkedInCount, + required this.lateCount, + }); + + final int totalNeeded; + final int totalAssigned; + final double totalCost; + final int checkedInCount; + final int lateCount; + + factory _LiveActivityData.empty() { + return const _LiveActivityData( + totalNeeded: 0, + totalAssigned: 0, + totalCost: 0, + checkedInCount: 0, + lateCount: 0, + ); + } +} + +class _LiveShiftAggregate { + _LiveShiftAggregate({ + required this.workersNeeded, + required this.assigned, + required this.cost, + }); + + final int workersNeeded; + final int assigned; + final double cost; +} diff --git a/backend/dataconnect/connector/application/queries.gql b/backend/dataconnect/connector/application/queries.gql index 6de03a97..dd0e0964 100644 --- a/backend/dataconnect/connector/application/queries.gql +++ b/backend/dataconnect/connector/application/queries.gql @@ -356,3 +356,48 @@ query listAcceptedApplicationsByBusinessForDay( staff { id fullName email phone photoUrl } } } + +#coverage list and today live +query listStaffsApplicationsByBusinessForDay( + $businessId: UUID! + $dayStart: Timestamp! + $dayEnd: Timestamp! + $offset: Int + $limit: Int +) @auth(level: USER) { + applications( + where: { + status: {in: [ACCEPTED, CONFIRMED, CHECKED_IN, CHECKED_OUT, LATE]} + shift: { + date: { ge: $dayStart, le: $dayEnd } + order: { businessId: { eq: $businessId } } + #status: { eq: ACCEPTED } + } + } + offset: $offset + limit: $limit + orderBy: { appliedAt: ASC } + ) { + id + shiftId + roleId + checkInTime + checkOutTime + appliedAt + status + + shiftRole{ + shift{ + location + cost + } + count + assigned + + role{ + name + } + } + staff { id fullName email phone photoUrl } + } +} \ No newline at end of file diff --git a/backend/dataconnect/connector/shiftRole/queries.gql b/backend/dataconnect/connector/shiftRole/queries.gql index 95b64d31..d2d23a8d 100644 --- a/backend/dataconnect/connector/shiftRole/queries.gql +++ b/backend/dataconnect/connector/shiftRole/queries.gql @@ -301,12 +301,14 @@ query listShiftRolesByBusinessAndDateRange( $end: Timestamp! $offset: Int $limit: Int + $status: ShiftStatus ) @auth(level: USER) { shiftRoles( where: { shift: { date: { ge: $start, le: $end } order: { businessId: { eq: $businessId } } + status: { eq: $status } } } offset: $offset @@ -462,3 +464,63 @@ query listShiftRolesByBusinessAndDatesSummary( role { id name } } } + +# ------------------------------------------------------------ +# BUSINESS: GET COMPLETED SHIFTS FOR A BUSINESS (via order.businessId) +# ------------------------------------------------------------ +#for spending insights in home view +query getCompletedShiftsByBusinessId( + $businessId: UUID! + $dateFrom: Timestamp! + $dateTo: Timestamp! + $offset: Int + $limit: Int +) @auth(level: USER) { + shifts( + where: { + order: { businessId: { eq: $businessId } } + status: {in: [IN_PROGRESS, CONFIRMED, COMPLETED, OPEN]} + date: { ge: $dateFrom, le: $dateTo } + } + offset: $offset + limit: $limit + ) { + id + #title + + #orderId + + date + startTime + endTime + hours + cost + + #location + #locationAddress + #latitude + #longitude + #description + + #status + workersNeeded + filled + #filledAt + + #managers + #durationDays + + createdAt + + order { + #id + #eventName + status + #orderType + #businessId + #vendorId + #business { id businessName email contactName } + #vendor { id companyName } + } + } +}