@@ -1,16 +1,16 @@
|
|||||||
# Basic Usage
|
# Basic Usage
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
ExampleConnector.instance.getStaffDocumentByKey(getStaffDocumentByKeyVariables).execute();
|
ExampleConnector.instance.createTeamMember(createTeamMemberVariables).execute();
|
||||||
ExampleConnector.instance.listStaffDocumentsByStaffId(listStaffDocumentsByStaffIdVariables).execute();
|
ExampleConnector.instance.updateTeamMember(updateTeamMemberVariables).execute();
|
||||||
ExampleConnector.instance.listStaffDocumentsByDocumentType(listStaffDocumentsByDocumentTypeVariables).execute();
|
ExampleConnector.instance.updateTeamMemberInviteStatus(updateTeamMemberInviteStatusVariables).execute();
|
||||||
ExampleConnector.instance.listStaffDocumentsByStatus(listStaffDocumentsByStatusVariables).execute();
|
ExampleConnector.instance.acceptInviteByCode(acceptInviteByCodeVariables).execute();
|
||||||
ExampleConnector.instance.createTeam(createTeamVariables).execute();
|
ExampleConnector.instance.cancelInviteByCode(cancelInviteByCodeVariables).execute();
|
||||||
ExampleConnector.instance.updateTeam(updateTeamVariables).execute();
|
ExampleConnector.instance.deleteTeamMember(deleteTeamMemberVariables).execute();
|
||||||
ExampleConnector.instance.deleteTeam(deleteTeamVariables).execute();
|
ExampleConnector.instance.listActivityLogs(listActivityLogsVariables).execute();
|
||||||
ExampleConnector.instance.listInvoiceTemplates(listInvoiceTemplatesVariables).execute();
|
ExampleConnector.instance.getActivityLogById(getActivityLogByIdVariables).execute();
|
||||||
ExampleConnector.instance.getInvoiceTemplateById(getInvoiceTemplateByIdVariables).execute();
|
ExampleConnector.instance.listActivityLogsByUserId(listActivityLogsByUserIdVariables).execute();
|
||||||
ExampleConnector.instance.listInvoiceTemplatesByOwnerId(listInvoiceTemplatesByOwnerIdVariables).execute();
|
ExampleConnector.instance.listUnreadActivityLogsByUserId(listUnreadActivityLogsByUserIdVariables).execute();
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -23,8 +23,8 @@ Optional fields can be discovered based on classes that have `Optional` object t
|
|||||||
This is an example of a mutation with an optional field:
|
This is an example of a mutation with an optional field:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
await ExampleConnector.instance.updateMessage({ ... })
|
await ExampleConnector.instance.getRapidOrders({ ... })
|
||||||
.conversationId(...)
|
.offset(...)
|
||||||
.execute();
|
.execute();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -164,6 +164,7 @@ class ListShiftRolesByBusinessAndDateRangeShiftRolesShift {
|
|||||||
final String? location;
|
final String? location;
|
||||||
final String? locationAddress;
|
final String? locationAddress;
|
||||||
final String title;
|
final String title;
|
||||||
|
final EnumValue<ShiftStatus>? status;
|
||||||
final ListShiftRolesByBusinessAndDateRangeShiftRolesShiftOrder order;
|
final ListShiftRolesByBusinessAndDateRangeShiftRolesShiftOrder order;
|
||||||
ListShiftRolesByBusinessAndDateRangeShiftRolesShift.fromJson(dynamic json):
|
ListShiftRolesByBusinessAndDateRangeShiftRolesShift.fromJson(dynamic json):
|
||||||
|
|
||||||
@@ -172,6 +173,7 @@ class ListShiftRolesByBusinessAndDateRangeShiftRolesShift {
|
|||||||
location = json['location'] == null ? null : nativeFromJson<String>(json['location']),
|
location = json['location'] == null ? null : nativeFromJson<String>(json['location']),
|
||||||
locationAddress = json['locationAddress'] == null ? null : nativeFromJson<String>(json['locationAddress']),
|
locationAddress = json['locationAddress'] == null ? null : nativeFromJson<String>(json['locationAddress']),
|
||||||
title = nativeFromJson<String>(json['title']),
|
title = nativeFromJson<String>(json['title']),
|
||||||
|
status = json['status'] == null ? null : shiftStatusDeserializer(json['status']),
|
||||||
order = ListShiftRolesByBusinessAndDateRangeShiftRolesShiftOrder.fromJson(json['order']);
|
order = ListShiftRolesByBusinessAndDateRangeShiftRolesShiftOrder.fromJson(json['order']);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
@@ -188,11 +190,12 @@ class ListShiftRolesByBusinessAndDateRangeShiftRolesShift {
|
|||||||
location == otherTyped.location &&
|
location == otherTyped.location &&
|
||||||
locationAddress == otherTyped.locationAddress &&
|
locationAddress == otherTyped.locationAddress &&
|
||||||
title == otherTyped.title &&
|
title == otherTyped.title &&
|
||||||
|
status == otherTyped.status &&
|
||||||
order == otherTyped.order;
|
order == otherTyped.order;
|
||||||
|
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([id.hashCode, date.hashCode, location.hashCode, locationAddress.hashCode, title.hashCode, order.hashCode]);
|
int get hashCode => Object.hashAll([id.hashCode, date.hashCode, location.hashCode, locationAddress.hashCode, title.hashCode, status.hashCode, order.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@@ -208,6 +211,11 @@ class ListShiftRolesByBusinessAndDateRangeShiftRolesShift {
|
|||||||
json['locationAddress'] = nativeToJson<String?>(locationAddress);
|
json['locationAddress'] = nativeToJson<String?>(locationAddress);
|
||||||
}
|
}
|
||||||
json['title'] = nativeToJson<String>(title);
|
json['title'] = nativeToJson<String>(title);
|
||||||
|
if (status != null) {
|
||||||
|
json['status'] =
|
||||||
|
shiftStatusSerializer(status!)
|
||||||
|
;
|
||||||
|
}
|
||||||
json['order'] = order.toJson();
|
json['order'] = order.toJson();
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@@ -218,6 +226,7 @@ class ListShiftRolesByBusinessAndDateRangeShiftRolesShift {
|
|||||||
this.location,
|
this.location,
|
||||||
this.locationAddress,
|
this.locationAddress,
|
||||||
required this.title,
|
required this.title,
|
||||||
|
this.status,
|
||||||
required this.order,
|
required this.order,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,404 @@
|
|||||||
|
part of 'generated.dart';
|
||||||
|
|
||||||
|
class ListShiftRolesByBusinessAndOrderVariablesBuilder {
|
||||||
|
String businessId;
|
||||||
|
String orderId;
|
||||||
|
Optional<int> _offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
Optional<int> _limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
|
||||||
|
final FirebaseDataConnect _dataConnect; ListShiftRolesByBusinessAndOrderVariablesBuilder offset(int? t) {
|
||||||
|
_offset.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
ListShiftRolesByBusinessAndOrderVariablesBuilder limit(int? t) {
|
||||||
|
_limit.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderVariablesBuilder(this._dataConnect, {required this.businessId,required this.orderId,});
|
||||||
|
Deserializer<ListShiftRolesByBusinessAndOrderData> dataDeserializer = (dynamic json) => ListShiftRolesByBusinessAndOrderData.fromJson(jsonDecode(json));
|
||||||
|
Serializer<ListShiftRolesByBusinessAndOrderVariables> varsSerializer = (ListShiftRolesByBusinessAndOrderVariables vars) => jsonEncode(vars.toJson());
|
||||||
|
Future<QueryResult<ListShiftRolesByBusinessAndOrderData, ListShiftRolesByBusinessAndOrderVariables>> execute() {
|
||||||
|
return ref().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryRef<ListShiftRolesByBusinessAndOrderData, ListShiftRolesByBusinessAndOrderVariables> ref() {
|
||||||
|
ListShiftRolesByBusinessAndOrderVariables vars= ListShiftRolesByBusinessAndOrderVariables(businessId: businessId,orderId: orderId,offset: _offset,limit: _limit,);
|
||||||
|
return _dataConnect.query("listShiftRolesByBusinessAndOrder", dataDeserializer, varsSerializer, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessAndOrderShiftRoles {
|
||||||
|
final String id;
|
||||||
|
final String shiftId;
|
||||||
|
final String roleId;
|
||||||
|
final int count;
|
||||||
|
final int? assigned;
|
||||||
|
final Timestamp? startTime;
|
||||||
|
final Timestamp? endTime;
|
||||||
|
final double? hours;
|
||||||
|
final EnumValue<BreakDuration>? breakType;
|
||||||
|
final double? totalValue;
|
||||||
|
final Timestamp? createdAt;
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRolesRole role;
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRolesShift shift;
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRoles.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
shiftId = nativeFromJson<String>(json['shiftId']),
|
||||||
|
roleId = nativeFromJson<String>(json['roleId']),
|
||||||
|
count = nativeFromJson<int>(json['count']),
|
||||||
|
assigned = json['assigned'] == null ? null : nativeFromJson<int>(json['assigned']),
|
||||||
|
startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']),
|
||||||
|
endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']),
|
||||||
|
hours = json['hours'] == null ? null : nativeFromJson<double>(json['hours']),
|
||||||
|
breakType = json['breakType'] == null ? null : breakDurationDeserializer(json['breakType']),
|
||||||
|
totalValue = json['totalValue'] == null ? null : nativeFromJson<double>(json['totalValue']),
|
||||||
|
createdAt = json['createdAt'] == null ? null : Timestamp.fromJson(json['createdAt']),
|
||||||
|
role = ListShiftRolesByBusinessAndOrderShiftRolesRole.fromJson(json['role']),
|
||||||
|
shift = ListShiftRolesByBusinessAndOrderShiftRolesShift.fromJson(json['shift']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRoles otherTyped = other as ListShiftRolesByBusinessAndOrderShiftRoles;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
shiftId == otherTyped.shiftId &&
|
||||||
|
roleId == otherTyped.roleId &&
|
||||||
|
count == otherTyped.count &&
|
||||||
|
assigned == otherTyped.assigned &&
|
||||||
|
startTime == otherTyped.startTime &&
|
||||||
|
endTime == otherTyped.endTime &&
|
||||||
|
hours == otherTyped.hours &&
|
||||||
|
breakType == otherTyped.breakType &&
|
||||||
|
totalValue == otherTyped.totalValue &&
|
||||||
|
createdAt == otherTyped.createdAt &&
|
||||||
|
role == otherTyped.role &&
|
||||||
|
shift == otherTyped.shift;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, shiftId.hashCode, roleId.hashCode, count.hashCode, assigned.hashCode, startTime.hashCode, endTime.hashCode, hours.hashCode, breakType.hashCode, totalValue.hashCode, createdAt.hashCode, role.hashCode, shift.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['shiftId'] = nativeToJson<String>(shiftId);
|
||||||
|
json['roleId'] = nativeToJson<String>(roleId);
|
||||||
|
json['count'] = nativeToJson<int>(count);
|
||||||
|
if (assigned != null) {
|
||||||
|
json['assigned'] = nativeToJson<int?>(assigned);
|
||||||
|
}
|
||||||
|
if (startTime != null) {
|
||||||
|
json['startTime'] = startTime!.toJson();
|
||||||
|
}
|
||||||
|
if (endTime != null) {
|
||||||
|
json['endTime'] = endTime!.toJson();
|
||||||
|
}
|
||||||
|
if (hours != null) {
|
||||||
|
json['hours'] = nativeToJson<double?>(hours);
|
||||||
|
}
|
||||||
|
if (breakType != null) {
|
||||||
|
json['breakType'] =
|
||||||
|
breakDurationSerializer(breakType!)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (totalValue != null) {
|
||||||
|
json['totalValue'] = nativeToJson<double?>(totalValue);
|
||||||
|
}
|
||||||
|
if (createdAt != null) {
|
||||||
|
json['createdAt'] = createdAt!.toJson();
|
||||||
|
}
|
||||||
|
json['role'] = role.toJson();
|
||||||
|
json['shift'] = shift.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRoles({
|
||||||
|
required this.id,
|
||||||
|
required this.shiftId,
|
||||||
|
required this.roleId,
|
||||||
|
required this.count,
|
||||||
|
this.assigned,
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.hours,
|
||||||
|
this.breakType,
|
||||||
|
this.totalValue,
|
||||||
|
this.createdAt,
|
||||||
|
required this.role,
|
||||||
|
required this.shift,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessAndOrderShiftRolesRole {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRolesRole.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
name = nativeFromJson<String>(json['name']),
|
||||||
|
costPerHour = nativeFromJson<double>(json['costPerHour']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRolesRole otherTyped = other as ListShiftRolesByBusinessAndOrderShiftRolesRole;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
name == otherTyped.name &&
|
||||||
|
costPerHour == otherTyped.costPerHour;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, name.hashCode, costPerHour.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['name'] = nativeToJson<String>(name);
|
||||||
|
json['costPerHour'] = nativeToJson<double>(costPerHour);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRolesRole({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessAndOrderShiftRolesShift {
|
||||||
|
final String id;
|
||||||
|
final String title;
|
||||||
|
final Timestamp? date;
|
||||||
|
final String orderId;
|
||||||
|
final String? location;
|
||||||
|
final String? locationAddress;
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder order;
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRolesShift.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
title = nativeFromJson<String>(json['title']),
|
||||||
|
date = json['date'] == null ? null : Timestamp.fromJson(json['date']),
|
||||||
|
orderId = nativeFromJson<String>(json['orderId']),
|
||||||
|
location = json['location'] == null ? null : nativeFromJson<String>(json['location']),
|
||||||
|
locationAddress = json['locationAddress'] == null ? null : nativeFromJson<String>(json['locationAddress']),
|
||||||
|
order = ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder.fromJson(json['order']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRolesShift otherTyped = other as ListShiftRolesByBusinessAndOrderShiftRolesShift;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
title == otherTyped.title &&
|
||||||
|
date == otherTyped.date &&
|
||||||
|
orderId == otherTyped.orderId &&
|
||||||
|
location == otherTyped.location &&
|
||||||
|
locationAddress == otherTyped.locationAddress &&
|
||||||
|
order == otherTyped.order;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, date.hashCode, orderId.hashCode, location.hashCode, locationAddress.hashCode, order.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['title'] = nativeToJson<String>(title);
|
||||||
|
if (date != null) {
|
||||||
|
json['date'] = date!.toJson();
|
||||||
|
}
|
||||||
|
json['orderId'] = nativeToJson<String>(orderId);
|
||||||
|
if (location != null) {
|
||||||
|
json['location'] = nativeToJson<String?>(location);
|
||||||
|
}
|
||||||
|
if (locationAddress != null) {
|
||||||
|
json['locationAddress'] = nativeToJson<String?>(locationAddress);
|
||||||
|
}
|
||||||
|
json['order'] = order.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRolesShift({
|
||||||
|
required this.id,
|
||||||
|
required this.title,
|
||||||
|
this.date,
|
||||||
|
required this.orderId,
|
||||||
|
this.location,
|
||||||
|
this.locationAddress,
|
||||||
|
required this.order,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder {
|
||||||
|
final String? vendorId;
|
||||||
|
final Timestamp? date;
|
||||||
|
final String? location;
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder.fromJson(dynamic json):
|
||||||
|
|
||||||
|
vendorId = json['vendorId'] == null ? null : nativeFromJson<String>(json['vendorId']),
|
||||||
|
date = json['date'] == null ? null : Timestamp.fromJson(json['date']),
|
||||||
|
location = json['location'] == null ? null : nativeFromJson<String>(json['location']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder otherTyped = other as ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder;
|
||||||
|
return vendorId == otherTyped.vendorId &&
|
||||||
|
date == otherTyped.date &&
|
||||||
|
location == otherTyped.location;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([vendorId.hashCode, date.hashCode, location.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
if (vendorId != null) {
|
||||||
|
json['vendorId'] = nativeToJson<String?>(vendorId);
|
||||||
|
}
|
||||||
|
if (date != null) {
|
||||||
|
json['date'] = date!.toJson();
|
||||||
|
}
|
||||||
|
if (location != null) {
|
||||||
|
json['location'] = nativeToJson<String?>(location);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder({
|
||||||
|
this.vendorId,
|
||||||
|
this.date,
|
||||||
|
this.location,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessAndOrderData {
|
||||||
|
final List<ListShiftRolesByBusinessAndOrderShiftRoles> shiftRoles;
|
||||||
|
ListShiftRolesByBusinessAndOrderData.fromJson(dynamic json):
|
||||||
|
|
||||||
|
shiftRoles = (json['shiftRoles'] as List<dynamic>)
|
||||||
|
.map((e) => ListShiftRolesByBusinessAndOrderShiftRoles.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessAndOrderData otherTyped = other as ListShiftRolesByBusinessAndOrderData;
|
||||||
|
return shiftRoles == otherTyped.shiftRoles;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => shiftRoles.hashCode;
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['shiftRoles'] = shiftRoles.map((e) => e.toJson()).toList();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderData({
|
||||||
|
required this.shiftRoles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessAndOrderVariables {
|
||||||
|
final String businessId;
|
||||||
|
final String orderId;
|
||||||
|
late final Optional<int>offset;
|
||||||
|
late final Optional<int>limit;
|
||||||
|
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
|
||||||
|
ListShiftRolesByBusinessAndOrderVariables.fromJson(Map<String, dynamic> json):
|
||||||
|
|
||||||
|
businessId = nativeFromJson<String>(json['businessId']),
|
||||||
|
orderId = nativeFromJson<String>(json['orderId']) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
offset.value = json['offset'] == null ? null : nativeFromJson<int>(json['offset']);
|
||||||
|
|
||||||
|
|
||||||
|
limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
limit.value = json['limit'] == null ? null : nativeFromJson<int>(json['limit']);
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessAndOrderVariables otherTyped = other as ListShiftRolesByBusinessAndOrderVariables;
|
||||||
|
return businessId == otherTyped.businessId &&
|
||||||
|
orderId == otherTyped.orderId &&
|
||||||
|
offset == otherTyped.offset &&
|
||||||
|
limit == otherTyped.limit;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([businessId.hashCode, orderId.hashCode, offset.hashCode, limit.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['businessId'] = nativeToJson<String>(businessId);
|
||||||
|
json['orderId'] = nativeToJson<String>(orderId);
|
||||||
|
if(offset.state == OptionalState.set) {
|
||||||
|
json['offset'] = offset.toJson();
|
||||||
|
}
|
||||||
|
if(limit.state == OptionalState.set) {
|
||||||
|
json['limit'] = limit.toJson();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessAndOrderVariables({
|
||||||
|
required this.businessId,
|
||||||
|
required this.orderId,
|
||||||
|
required this.offset,
|
||||||
|
required this.limit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,385 @@
|
|||||||
|
part of 'generated.dart';
|
||||||
|
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersVariablesBuilder {
|
||||||
|
String businessId;
|
||||||
|
Timestamp start;
|
||||||
|
Timestamp end;
|
||||||
|
Optional<int> _offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
Optional<int> _limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
|
||||||
|
final FirebaseDataConnect _dataConnect; ListShiftRolesByBusinessDateRangeCompletedOrdersVariablesBuilder offset(int? t) {
|
||||||
|
_offset.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersVariablesBuilder limit(int? t) {
|
||||||
|
_limit.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersVariablesBuilder(this._dataConnect, {required this.businessId,required this.start,required this.end,});
|
||||||
|
Deserializer<ListShiftRolesByBusinessDateRangeCompletedOrdersData> dataDeserializer = (dynamic json) => ListShiftRolesByBusinessDateRangeCompletedOrdersData.fromJson(jsonDecode(json));
|
||||||
|
Serializer<ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> varsSerializer = (ListShiftRolesByBusinessDateRangeCompletedOrdersVariables vars) => jsonEncode(vars.toJson());
|
||||||
|
Future<QueryResult<ListShiftRolesByBusinessDateRangeCompletedOrdersData, ListShiftRolesByBusinessDateRangeCompletedOrdersVariables>> execute() {
|
||||||
|
return ref().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryRef<ListShiftRolesByBusinessDateRangeCompletedOrdersData, ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> ref() {
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersVariables vars= ListShiftRolesByBusinessDateRangeCompletedOrdersVariables(businessId: businessId,start: start,end: end,offset: _offset,limit: _limit,);
|
||||||
|
return _dataConnect.query("listShiftRolesByBusinessDateRangeCompletedOrders", dataDeserializer, varsSerializer, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles {
|
||||||
|
final String shiftId;
|
||||||
|
final String roleId;
|
||||||
|
final int count;
|
||||||
|
final int? assigned;
|
||||||
|
final double? hours;
|
||||||
|
final Timestamp? startTime;
|
||||||
|
final Timestamp? endTime;
|
||||||
|
final double? totalValue;
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole role;
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift shift;
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles.fromJson(dynamic json):
|
||||||
|
|
||||||
|
shiftId = nativeFromJson<String>(json['shiftId']),
|
||||||
|
roleId = nativeFromJson<String>(json['roleId']),
|
||||||
|
count = nativeFromJson<int>(json['count']),
|
||||||
|
assigned = json['assigned'] == null ? null : nativeFromJson<int>(json['assigned']),
|
||||||
|
hours = json['hours'] == null ? null : nativeFromJson<double>(json['hours']),
|
||||||
|
startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']),
|
||||||
|
endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']),
|
||||||
|
totalValue = json['totalValue'] == null ? null : nativeFromJson<double>(json['totalValue']),
|
||||||
|
role = ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole.fromJson(json['role']),
|
||||||
|
shift = ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift.fromJson(json['shift']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles otherTyped = other as ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles;
|
||||||
|
return shiftId == otherTyped.shiftId &&
|
||||||
|
roleId == otherTyped.roleId &&
|
||||||
|
count == otherTyped.count &&
|
||||||
|
assigned == otherTyped.assigned &&
|
||||||
|
hours == otherTyped.hours &&
|
||||||
|
startTime == otherTyped.startTime &&
|
||||||
|
endTime == otherTyped.endTime &&
|
||||||
|
totalValue == otherTyped.totalValue &&
|
||||||
|
role == otherTyped.role &&
|
||||||
|
shift == otherTyped.shift;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([shiftId.hashCode, roleId.hashCode, count.hashCode, assigned.hashCode, hours.hashCode, startTime.hashCode, endTime.hashCode, totalValue.hashCode, role.hashCode, shift.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['shiftId'] = nativeToJson<String>(shiftId);
|
||||||
|
json['roleId'] = nativeToJson<String>(roleId);
|
||||||
|
json['count'] = nativeToJson<int>(count);
|
||||||
|
if (assigned != null) {
|
||||||
|
json['assigned'] = nativeToJson<int?>(assigned);
|
||||||
|
}
|
||||||
|
if (hours != null) {
|
||||||
|
json['hours'] = nativeToJson<double?>(hours);
|
||||||
|
}
|
||||||
|
if (startTime != null) {
|
||||||
|
json['startTime'] = startTime!.toJson();
|
||||||
|
}
|
||||||
|
if (endTime != null) {
|
||||||
|
json['endTime'] = endTime!.toJson();
|
||||||
|
}
|
||||||
|
if (totalValue != null) {
|
||||||
|
json['totalValue'] = nativeToJson<double?>(totalValue);
|
||||||
|
}
|
||||||
|
json['role'] = role.toJson();
|
||||||
|
json['shift'] = shift.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles({
|
||||||
|
required this.shiftId,
|
||||||
|
required this.roleId,
|
||||||
|
required this.count,
|
||||||
|
this.assigned,
|
||||||
|
this.hours,
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.totalValue,
|
||||||
|
required this.role,
|
||||||
|
required this.shift,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
name = nativeFromJson<String>(json['name']),
|
||||||
|
costPerHour = nativeFromJson<double>(json['costPerHour']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole otherTyped = other as ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
name == otherTyped.name &&
|
||||||
|
costPerHour == otherTyped.costPerHour;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, name.hashCode, costPerHour.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['name'] = nativeToJson<String>(name);
|
||||||
|
json['costPerHour'] = nativeToJson<double>(costPerHour);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesRole({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift {
|
||||||
|
final String id;
|
||||||
|
final Timestamp? date;
|
||||||
|
final String? location;
|
||||||
|
final String? locationAddress;
|
||||||
|
final String title;
|
||||||
|
final EnumValue<ShiftStatus>? status;
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder order;
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
date = json['date'] == null ? null : Timestamp.fromJson(json['date']),
|
||||||
|
location = json['location'] == null ? null : nativeFromJson<String>(json['location']),
|
||||||
|
locationAddress = json['locationAddress'] == null ? null : nativeFromJson<String>(json['locationAddress']),
|
||||||
|
title = nativeFromJson<String>(json['title']),
|
||||||
|
status = json['status'] == null ? null : shiftStatusDeserializer(json['status']),
|
||||||
|
order = ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder.fromJson(json['order']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift otherTyped = other as ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
date == otherTyped.date &&
|
||||||
|
location == otherTyped.location &&
|
||||||
|
locationAddress == otherTyped.locationAddress &&
|
||||||
|
title == otherTyped.title &&
|
||||||
|
status == otherTyped.status &&
|
||||||
|
order == otherTyped.order;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, date.hashCode, location.hashCode, locationAddress.hashCode, title.hashCode, status.hashCode, order.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
if (date != null) {
|
||||||
|
json['date'] = date!.toJson();
|
||||||
|
}
|
||||||
|
if (location != null) {
|
||||||
|
json['location'] = nativeToJson<String?>(location);
|
||||||
|
}
|
||||||
|
if (locationAddress != null) {
|
||||||
|
json['locationAddress'] = nativeToJson<String?>(locationAddress);
|
||||||
|
}
|
||||||
|
json['title'] = nativeToJson<String>(title);
|
||||||
|
if (status != null) {
|
||||||
|
json['status'] =
|
||||||
|
shiftStatusSerializer(status!)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
json['order'] = order.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShift({
|
||||||
|
required this.id,
|
||||||
|
this.date,
|
||||||
|
this.location,
|
||||||
|
this.locationAddress,
|
||||||
|
required this.title,
|
||||||
|
this.status,
|
||||||
|
required this.order,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder {
|
||||||
|
final String id;
|
||||||
|
final EnumValue<OrderType> orderType;
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
orderType = orderTypeDeserializer(json['orderType']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder otherTyped = other as ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
orderType == otherTyped.orderType;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, orderType.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['orderType'] =
|
||||||
|
orderTypeSerializer(orderType)
|
||||||
|
;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRolesShiftOrder({
|
||||||
|
required this.id,
|
||||||
|
required this.orderType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersData {
|
||||||
|
final List<ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles> shiftRoles;
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersData.fromJson(dynamic json):
|
||||||
|
|
||||||
|
shiftRoles = (json['shiftRoles'] as List<dynamic>)
|
||||||
|
.map((e) => ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersData otherTyped = other as ListShiftRolesByBusinessDateRangeCompletedOrdersData;
|
||||||
|
return shiftRoles == otherTyped.shiftRoles;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => shiftRoles.hashCode;
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['shiftRoles'] = shiftRoles.map((e) => e.toJson()).toList();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersData({
|
||||||
|
required this.shiftRoles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListShiftRolesByBusinessDateRangeCompletedOrdersVariables {
|
||||||
|
final String businessId;
|
||||||
|
final Timestamp start;
|
||||||
|
final Timestamp end;
|
||||||
|
late final Optional<int>offset;
|
||||||
|
late final Optional<int>limit;
|
||||||
|
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersVariables.fromJson(Map<String, dynamic> json):
|
||||||
|
|
||||||
|
businessId = nativeFromJson<String>(json['businessId']),
|
||||||
|
start = Timestamp.fromJson(json['start']),
|
||||||
|
end = Timestamp.fromJson(json['end']) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
offset.value = json['offset'] == null ? null : nativeFromJson<int>(json['offset']);
|
||||||
|
|
||||||
|
|
||||||
|
limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
limit.value = json['limit'] == null ? null : nativeFromJson<int>(json['limit']);
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListShiftRolesByBusinessDateRangeCompletedOrdersVariables otherTyped = other as ListShiftRolesByBusinessDateRangeCompletedOrdersVariables;
|
||||||
|
return businessId == otherTyped.businessId &&
|
||||||
|
start == otherTyped.start &&
|
||||||
|
end == otherTyped.end &&
|
||||||
|
offset == otherTyped.offset &&
|
||||||
|
limit == otherTyped.limit;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([businessId.hashCode, start.hashCode, end.hashCode, offset.hashCode, limit.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['businessId'] = nativeToJson<String>(businessId);
|
||||||
|
json['start'] = start.toJson();
|
||||||
|
json['end'] = end.toJson();
|
||||||
|
if(offset.state == OptionalState.set) {
|
||||||
|
json['offset'] = offset.toJson();
|
||||||
|
}
|
||||||
|
if(limit.state == OptionalState.set) {
|
||||||
|
json['limit'] = limit.toJson();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersVariables({
|
||||||
|
required this.businessId,
|
||||||
|
required this.start,
|
||||||
|
required this.end,
|
||||||
|
required this.offset,
|
||||||
|
required this.limit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@ class UpdateOrderVariablesBuilder {
|
|||||||
Optional<String> _businessId = Optional.optional(nativeFromJson, nativeToJson);
|
Optional<String> _businessId = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
Optional<String> _location = Optional.optional(nativeFromJson, nativeToJson);
|
Optional<String> _location = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
Optional<OrderStatus> _status = Optional.optional((data) => OrderStatus.values.byName(data), enumSerializer);
|
Optional<OrderStatus> _status = Optional.optional((data) => OrderStatus.values.byName(data), enumSerializer);
|
||||||
|
Optional<Timestamp> _date = Optional.optional((json) => json['date'] = Timestamp.fromJson(json['date']), defaultSerializer);
|
||||||
Optional<Timestamp> _startDate = Optional.optional((json) => json['startDate'] = Timestamp.fromJson(json['startDate']), defaultSerializer);
|
Optional<Timestamp> _startDate = Optional.optional((json) => json['startDate'] = Timestamp.fromJson(json['startDate']), defaultSerializer);
|
||||||
Optional<Timestamp> _endDate = Optional.optional((json) => json['endDate'] = Timestamp.fromJson(json['endDate']), defaultSerializer);
|
Optional<Timestamp> _endDate = Optional.optional((json) => json['endDate'] = Timestamp.fromJson(json['endDate']), defaultSerializer);
|
||||||
Optional<double> _total = Optional.optional(nativeFromJson, nativeToJson);
|
Optional<double> _total = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
@@ -36,6 +37,10 @@ class UpdateOrderVariablesBuilder {
|
|||||||
_status.value = t;
|
_status.value = t;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
UpdateOrderVariablesBuilder date(Timestamp? t) {
|
||||||
|
_date.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
UpdateOrderVariablesBuilder startDate(Timestamp? t) {
|
UpdateOrderVariablesBuilder startDate(Timestamp? t) {
|
||||||
_startDate.value = t;
|
_startDate.value = t;
|
||||||
return this;
|
return this;
|
||||||
@@ -97,7 +102,7 @@ class UpdateOrderVariablesBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MutationRef<UpdateOrderData, UpdateOrderVariables> ref() {
|
MutationRef<UpdateOrderData, UpdateOrderVariables> ref() {
|
||||||
UpdateOrderVariables vars= UpdateOrderVariables(id: id,vendorId: _vendorId,businessId: _businessId,location: _location,status: _status,startDate: _startDate,endDate: _endDate,total: _total,eventName: _eventName,assignedStaff: _assignedStaff,shifts: _shifts,requested: _requested,hub: _hub,recurringDays: _recurringDays,permanentDays: _permanentDays,notes: _notes,detectedConflicts: _detectedConflicts,poReference: _poReference,);
|
UpdateOrderVariables vars= UpdateOrderVariables(id: id,vendorId: _vendorId,businessId: _businessId,location: _location,status: _status,date: _date,startDate: _startDate,endDate: _endDate,total: _total,eventName: _eventName,assignedStaff: _assignedStaff,shifts: _shifts,requested: _requested,hub: _hub,recurringDays: _recurringDays,permanentDays: _permanentDays,notes: _notes,detectedConflicts: _detectedConflicts,poReference: _poReference,);
|
||||||
return _dataConnect.mutation("updateOrder", dataDeserializer, varsSerializer, vars);
|
return _dataConnect.mutation("updateOrder", dataDeserializer, varsSerializer, vars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +184,7 @@ class UpdateOrderVariables {
|
|||||||
late final Optional<String>businessId;
|
late final Optional<String>businessId;
|
||||||
late final Optional<String>location;
|
late final Optional<String>location;
|
||||||
late final Optional<OrderStatus>status;
|
late final Optional<OrderStatus>status;
|
||||||
|
late final Optional<Timestamp>date;
|
||||||
late final Optional<Timestamp>startDate;
|
late final Optional<Timestamp>startDate;
|
||||||
late final Optional<Timestamp>endDate;
|
late final Optional<Timestamp>endDate;
|
||||||
late final Optional<double>total;
|
late final Optional<double>total;
|
||||||
@@ -215,6 +221,10 @@ class UpdateOrderVariables {
|
|||||||
status.value = json['status'] == null ? null : OrderStatus.values.byName(json['status']);
|
status.value = json['status'] == null ? null : OrderStatus.values.byName(json['status']);
|
||||||
|
|
||||||
|
|
||||||
|
date = Optional.optional((json) => json['date'] = Timestamp.fromJson(json['date']), defaultSerializer);
|
||||||
|
date.value = json['date'] == null ? null : Timestamp.fromJson(json['date']);
|
||||||
|
|
||||||
|
|
||||||
startDate = Optional.optional((json) => json['startDate'] = Timestamp.fromJson(json['startDate']), defaultSerializer);
|
startDate = Optional.optional((json) => json['startDate'] = Timestamp.fromJson(json['startDate']), defaultSerializer);
|
||||||
startDate.value = json['startDate'] == null ? null : Timestamp.fromJson(json['startDate']);
|
startDate.value = json['startDate'] == null ? null : Timestamp.fromJson(json['startDate']);
|
||||||
|
|
||||||
@@ -282,6 +292,7 @@ class UpdateOrderVariables {
|
|||||||
businessId == otherTyped.businessId &&
|
businessId == otherTyped.businessId &&
|
||||||
location == otherTyped.location &&
|
location == otherTyped.location &&
|
||||||
status == otherTyped.status &&
|
status == otherTyped.status &&
|
||||||
|
date == otherTyped.date &&
|
||||||
startDate == otherTyped.startDate &&
|
startDate == otherTyped.startDate &&
|
||||||
endDate == otherTyped.endDate &&
|
endDate == otherTyped.endDate &&
|
||||||
total == otherTyped.total &&
|
total == otherTyped.total &&
|
||||||
@@ -298,7 +309,7 @@ class UpdateOrderVariables {
|
|||||||
|
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([id.hashCode, vendorId.hashCode, businessId.hashCode, location.hashCode, status.hashCode, startDate.hashCode, endDate.hashCode, total.hashCode, eventName.hashCode, assignedStaff.hashCode, shifts.hashCode, requested.hashCode, hub.hashCode, recurringDays.hashCode, permanentDays.hashCode, notes.hashCode, detectedConflicts.hashCode, poReference.hashCode]);
|
int get hashCode => Object.hashAll([id.hashCode, vendorId.hashCode, businessId.hashCode, location.hashCode, status.hashCode, date.hashCode, startDate.hashCode, endDate.hashCode, total.hashCode, eventName.hashCode, assignedStaff.hashCode, shifts.hashCode, requested.hashCode, hub.hashCode, recurringDays.hashCode, permanentDays.hashCode, notes.hashCode, detectedConflicts.hashCode, poReference.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@@ -316,6 +327,9 @@ class UpdateOrderVariables {
|
|||||||
if(status.state == OptionalState.set) {
|
if(status.state == OptionalState.set) {
|
||||||
json['status'] = status.toJson();
|
json['status'] = status.toJson();
|
||||||
}
|
}
|
||||||
|
if(date.state == OptionalState.set) {
|
||||||
|
json['date'] = date.toJson();
|
||||||
|
}
|
||||||
if(startDate.state == OptionalState.set) {
|
if(startDate.state == OptionalState.set) {
|
||||||
json['startDate'] = startDate.toJson();
|
json['startDate'] = startDate.toJson();
|
||||||
}
|
}
|
||||||
@@ -364,6 +378,7 @@ class UpdateOrderVariables {
|
|||||||
required this.businessId,
|
required this.businessId,
|
||||||
required this.location,
|
required this.location,
|
||||||
required this.status,
|
required this.status,
|
||||||
|
required this.date,
|
||||||
required this.startDate,
|
required this.startDate,
|
||||||
required this.endDate,
|
required this.endDate,
|
||||||
required this.total,
|
required this.total,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class OrderRepositoryMock {
|
|||||||
return <OrderItem>[
|
return <OrderItem>[
|
||||||
OrderItem(
|
OrderItem(
|
||||||
id: '1',
|
id: '1',
|
||||||
|
orderId: 'order_1',
|
||||||
title: 'Server - Wedding',
|
title: 'Server - Wedding',
|
||||||
clientName: 'Grand Plaza Hotel',
|
clientName: 'Grand Plaza Hotel',
|
||||||
status: 'filled',
|
status: 'filled',
|
||||||
@@ -75,6 +76,7 @@ class OrderRepositoryMock {
|
|||||||
),
|
),
|
||||||
OrderItem(
|
OrderItem(
|
||||||
id: '2',
|
id: '2',
|
||||||
|
orderId: 'order_2',
|
||||||
title: 'Bartender - Private Event',
|
title: 'Bartender - Private Event',
|
||||||
clientName: 'Taste of the Town',
|
clientName: 'Taste of the Town',
|
||||||
status: 'open',
|
status: 'open',
|
||||||
@@ -101,6 +103,7 @@ class OrderRepositoryMock {
|
|||||||
),
|
),
|
||||||
OrderItem(
|
OrderItem(
|
||||||
id: '3',
|
id: '3',
|
||||||
|
orderId: 'order_3',
|
||||||
title: 'Event Staff',
|
title: 'Event Staff',
|
||||||
clientName: 'City Center',
|
clientName: 'City Center',
|
||||||
status: 'in_progress',
|
status: 'in_progress',
|
||||||
@@ -125,6 +128,7 @@ class OrderRepositoryMock {
|
|||||||
),
|
),
|
||||||
OrderItem(
|
OrderItem(
|
||||||
id: '4',
|
id: '4',
|
||||||
|
orderId: 'order_4',
|
||||||
title: 'Coat Check',
|
title: 'Coat Check',
|
||||||
clientName: 'The Met Museum',
|
clientName: 'The Met Museum',
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
|
|||||||
@@ -66,3 +66,4 @@ export 'src/entities/support/working_area.dart';
|
|||||||
|
|
||||||
// Home
|
// Home
|
||||||
export 'src/entities/home/home_dashboard_data.dart';
|
export 'src/entities/home/home_dashboard_data.dart';
|
||||||
|
export 'src/entities/home/reorder_item.dart';
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
/// Summary of a completed shift role used for reorder suggestions.
|
||||||
|
class ReorderItem extends Equatable {
|
||||||
|
const ReorderItem({
|
||||||
|
required this.orderId,
|
||||||
|
required this.title,
|
||||||
|
required this.location,
|
||||||
|
required this.hourlyRate,
|
||||||
|
required this.hours,
|
||||||
|
required this.workers,
|
||||||
|
required this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Parent order id for the completed shift.
|
||||||
|
final String orderId;
|
||||||
|
|
||||||
|
/// Display title (role + shift title).
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
/// Location from the shift.
|
||||||
|
final String location;
|
||||||
|
|
||||||
|
/// Hourly rate from the role.
|
||||||
|
final double hourlyRate;
|
||||||
|
|
||||||
|
/// Total hours for the shift role.
|
||||||
|
final double hours;
|
||||||
|
|
||||||
|
/// Worker count for the shift role.
|
||||||
|
final int workers;
|
||||||
|
|
||||||
|
/// Order type (e.g., ONE_TIME).
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => <Object?>[
|
||||||
|
orderId,
|
||||||
|
title,
|
||||||
|
location,
|
||||||
|
hourlyRate,
|
||||||
|
hours,
|
||||||
|
workers,
|
||||||
|
type,
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ class OneTimeOrderPosition extends Equatable {
|
|||||||
required this.count,
|
required this.count,
|
||||||
required this.startTime,
|
required this.startTime,
|
||||||
required this.endTime,
|
required this.endTime,
|
||||||
this.lunchBreak = 30,
|
this.lunchBreak = 'NO_BREAK',
|
||||||
this.location,
|
this.location,
|
||||||
});
|
});
|
||||||
/// The job role or title required.
|
/// The job role or title required.
|
||||||
@@ -25,8 +25,8 @@ class OneTimeOrderPosition extends Equatable {
|
|||||||
/// The scheduled end time (e.g., "05:00 PM").
|
/// The scheduled end time (e.g., "05:00 PM").
|
||||||
final String endTime;
|
final String endTime;
|
||||||
|
|
||||||
/// The duration of the lunch break in minutes. Defaults to 30.
|
/// The break duration enum value (e.g., NO_BREAK, MIN_15, MIN_30).
|
||||||
final int lunchBreak;
|
final String lunchBreak;
|
||||||
|
|
||||||
/// Optional specific location for this position, if different from the order's main location.
|
/// Optional specific location for this position, if different from the order's main location.
|
||||||
final String? location;
|
final String? location;
|
||||||
@@ -47,7 +47,7 @@ class OneTimeOrderPosition extends Equatable {
|
|||||||
int? count,
|
int? count,
|
||||||
String? startTime,
|
String? startTime,
|
||||||
String? endTime,
|
String? endTime,
|
||||||
int? lunchBreak,
|
String? lunchBreak,
|
||||||
String? location,
|
String? location,
|
||||||
}) {
|
}) {
|
||||||
return OneTimeOrderPosition(
|
return OneTimeOrderPosition(
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class OrderItem extends Equatable {
|
|||||||
/// Creates an [OrderItem].
|
/// Creates an [OrderItem].
|
||||||
const OrderItem({
|
const OrderItem({
|
||||||
required this.id,
|
required this.id,
|
||||||
|
required this.orderId,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.clientName,
|
required this.clientName,
|
||||||
required this.status,
|
required this.status,
|
||||||
@@ -27,6 +28,9 @@ class OrderItem extends Equatable {
|
|||||||
/// Unique identifier of the order.
|
/// Unique identifier of the order.
|
||||||
final String id;
|
final String id;
|
||||||
|
|
||||||
|
/// Parent order identifier.
|
||||||
|
final String orderId;
|
||||||
|
|
||||||
/// Title or name of the role.
|
/// Title or name of the role.
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
@@ -72,6 +76,7 @@ class OrderItem extends Equatable {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => <Object?>[
|
List<Object?> get props => <Object?>[
|
||||||
id,
|
id,
|
||||||
|
orderId,
|
||||||
title,
|
title,
|
||||||
clientName,
|
clientName,
|
||||||
status,
|
status,
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ class ClientCreateOrderRepositoryImpl
|
|||||||
.startTime(_toTimestamp(start))
|
.startTime(_toTimestamp(start))
|
||||||
.endTime(_toTimestamp(normalizedEnd))
|
.endTime(_toTimestamp(normalizedEnd))
|
||||||
.hours(hours)
|
.hours(hours)
|
||||||
|
.breakType(_breakDurationFromValue(position.lunchBreak))
|
||||||
.totalValue(totalValue)
|
.totalValue(totalValue)
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
@@ -148,6 +149,17 @@ class ClientCreateOrderRepositoryImpl
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dc.BreakDuration _breakDurationFromValue(String value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'MIN_15':
|
||||||
|
return dc.BreakDuration.MIN_15;
|
||||||
|
case 'MIN_30':
|
||||||
|
return dc.BreakDuration.MIN_30;
|
||||||
|
default:
|
||||||
|
return dc.BreakDuration.NO_BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DateTime _parseTime(DateTime date, String time) {
|
DateTime _parseTime(DateTime date, String time) {
|
||||||
if (time.trim().isEmpty) {
|
if (time.trim().isEmpty) {
|
||||||
throw Exception('Shift time is missing.');
|
throw Exception('Shift time is missing.');
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
|||||||
border: Border.all(color: UiColors.border),
|
border: Border.all(color: UiColors.border),
|
||||||
),
|
),
|
||||||
child: DropdownButtonHideUnderline(
|
child: DropdownButtonHideUnderline(
|
||||||
child: DropdownButton<int>(
|
child: DropdownButton<String>(
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
value: position.lunchBreak,
|
value: position.lunchBreak,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
@@ -238,16 +238,23 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
|||||||
size: 18,
|
size: 18,
|
||||||
color: UiColors.iconSecondary,
|
color: UiColors.iconSecondary,
|
||||||
),
|
),
|
||||||
onChanged: (int? val) {
|
onChanged: (String? val) {
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
onUpdated(position.copyWith(lunchBreak: val));
|
onUpdated(position.copyWith(lunchBreak: val));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
items: <int>[0, 15, 30, 45, 60].map((int mins) {
|
items: <String>['NO_BREAK', 'MIN_15', 'MIN_30'].map((
|
||||||
return DropdownMenuItem<int>(
|
String value,
|
||||||
value: mins,
|
) {
|
||||||
|
final String label = switch (value) {
|
||||||
|
'NO_BREAK' => 'No Break',
|
||||||
|
'MIN_15' => '15 min',
|
||||||
|
_ => '30 min',
|
||||||
|
};
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
child: Text(
|
child: Text(
|
||||||
mins == 0 ? 'No Break' : '$mins mins',
|
label,
|
||||||
style: UiTypography.body2r.textPrimary,
|
style: UiTypography.body2r.textPrimary,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:krow_data_connect/krow_data_connect.dart';
|
|||||||
import 'src/data/repositories_impl/home_repository_impl.dart';
|
import 'src/data/repositories_impl/home_repository_impl.dart';
|
||||||
import 'src/domain/repositories/home_repository_interface.dart';
|
import 'src/domain/repositories/home_repository_interface.dart';
|
||||||
import 'src/domain/usecases/get_dashboard_data_usecase.dart';
|
import 'src/domain/usecases/get_dashboard_data_usecase.dart';
|
||||||
|
import 'src/domain/usecases/get_recent_reorders_usecase.dart';
|
||||||
import 'src/domain/usecases/get_user_session_data_usecase.dart';
|
import 'src/domain/usecases/get_user_session_data_usecase.dart';
|
||||||
import 'src/presentation/blocs/client_home_bloc.dart';
|
import 'src/presentation/blocs/client_home_bloc.dart';
|
||||||
import 'src/presentation/pages/client_home_page.dart';
|
import 'src/presentation/pages/client_home_page.dart';
|
||||||
@@ -24,17 +25,22 @@ class ClientHomeModule extends Module {
|
|||||||
void binds(Injector i) {
|
void binds(Injector i) {
|
||||||
// Repositories
|
// Repositories
|
||||||
i.addLazySingleton<HomeRepositoryInterface>(
|
i.addLazySingleton<HomeRepositoryInterface>(
|
||||||
() => HomeRepositoryImpl(i.get<HomeRepositoryMock>()),
|
() => HomeRepositoryImpl(
|
||||||
|
i.get<HomeRepositoryMock>(),
|
||||||
|
ExampleConnector.instance,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// UseCases
|
// UseCases
|
||||||
i.addLazySingleton(GetDashboardDataUseCase.new);
|
i.addLazySingleton(GetDashboardDataUseCase.new);
|
||||||
|
i.addLazySingleton(GetRecentReordersUseCase.new);
|
||||||
i.addLazySingleton(GetUserSessionDataUseCase.new);
|
i.addLazySingleton(GetUserSessionDataUseCase.new);
|
||||||
|
|
||||||
// BLoCs
|
// BLoCs
|
||||||
i.add<ClientHomeBloc>(
|
i.add<ClientHomeBloc>(
|
||||||
() => ClientHomeBloc(
|
() => ClientHomeBloc(
|
||||||
getDashboardDataUseCase: i.get<GetDashboardDataUseCase>(),
|
getDashboardDataUseCase: i.get<GetDashboardDataUseCase>(),
|
||||||
|
getRecentReordersUseCase: i.get<GetRecentReordersUseCase>(),
|
||||||
getUserSessionDataUseCase: i.get<GetUserSessionDataUseCase>(),
|
getUserSessionDataUseCase: i.get<GetUserSessionDataUseCase>(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
import '../../domain/repositories/home_repository_interface.dart';
|
import '../../domain/repositories/home_repository_interface.dart';
|
||||||
@@ -8,11 +9,12 @@ import '../../domain/repositories/home_repository_interface.dart';
|
|||||||
/// domain layer and the data source (in this case, a mock from data_connect).
|
/// domain layer and the data source (in this case, a mock from data_connect).
|
||||||
class HomeRepositoryImpl implements HomeRepositoryInterface {
|
class HomeRepositoryImpl implements HomeRepositoryInterface {
|
||||||
final HomeRepositoryMock _mock;
|
final HomeRepositoryMock _mock;
|
||||||
|
final ExampleConnector _dataConnect;
|
||||||
|
|
||||||
/// Creates a [HomeRepositoryImpl].
|
/// Creates a [HomeRepositoryImpl].
|
||||||
///
|
///
|
||||||
/// Requires a [HomeRepositoryMock] to perform data operations.
|
/// Requires a [HomeRepositoryMock] to perform data operations.
|
||||||
HomeRepositoryImpl(this._mock);
|
HomeRepositoryImpl(this._mock, this._dataConnect);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<HomeDashboardData> getDashboardData() {
|
Future<HomeDashboardData> getDashboardData() {
|
||||||
@@ -27,4 +29,62 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
|
|||||||
photoUrl: photoUrl,
|
photoUrl: photoUrl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ReorderItem>> getRecentReorders() async {
|
||||||
|
final String? businessId = ClientSessionStore.instance.session?.business?.id;
|
||||||
|
if (businessId == null || businessId.isEmpty) {
|
||||||
|
return const <ReorderItem>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateTime now = DateTime.now();
|
||||||
|
final DateTime start = now.subtract(const Duration(days: 30));
|
||||||
|
final fdc.Timestamp startTimestamp = _toTimestamp(start);
|
||||||
|
final fdc.Timestamp endTimestamp = _toTimestamp(now);
|
||||||
|
|
||||||
|
final fdc.QueryResult<
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersData,
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> result =
|
||||||
|
await _dataConnect.listShiftRolesByBusinessDateRangeCompletedOrders(
|
||||||
|
businessId: businessId,
|
||||||
|
start: startTimestamp,
|
||||||
|
end: endTimestamp,
|
||||||
|
).execute();
|
||||||
|
|
||||||
|
print(
|
||||||
|
'Home reorder: completed shiftRoles=${result.data.shiftRoles.length}',
|
||||||
|
);
|
||||||
|
|
||||||
|
return result.data.shiftRoles.map((
|
||||||
|
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles shiftRole,
|
||||||
|
) {
|
||||||
|
print(
|
||||||
|
'Home reorder item: orderId=${shiftRole.shift.order.id} '
|
||||||
|
'shiftId=${shiftRole.shiftId} roleId=${shiftRole.roleId} '
|
||||||
|
'orderType=${shiftRole.shift.order.orderType.stringValue} '
|
||||||
|
'hours=${shiftRole.hours} count=${shiftRole.count}',
|
||||||
|
);
|
||||||
|
final String location =
|
||||||
|
shiftRole.shift.location ??
|
||||||
|
shiftRole.shift.locationAddress ??
|
||||||
|
'';
|
||||||
|
final String type = shiftRole.shift.order.orderType.stringValue;
|
||||||
|
return ReorderItem(
|
||||||
|
orderId: shiftRole.shift.order.id,
|
||||||
|
title: '${shiftRole.role.name} - ${shiftRole.shift.title}',
|
||||||
|
location: location,
|
||||||
|
hourlyRate: shiftRole.role.costPerHour,
|
||||||
|
hours: shiftRole.hours ?? 0,
|
||||||
|
workers: shiftRole.count,
|
||||||
|
type: type,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
fdc.Timestamp _toTimestamp(DateTime date) {
|
||||||
|
final int millis = date.millisecondsSinceEpoch;
|
||||||
|
final int seconds = millis ~/ 1000;
|
||||||
|
final int nanos = (millis % 1000) * 1000000;
|
||||||
|
return fdc.Timestamp(nanos, seconds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,7 @@ abstract interface class HomeRepositoryInterface {
|
|||||||
|
|
||||||
/// Fetches the user's session data (business name and photo).
|
/// Fetches the user's session data (business name and photo).
|
||||||
UserSessionData getUserSessionData();
|
UserSessionData getUserSessionData();
|
||||||
|
|
||||||
|
/// Fetches recently completed shift roles for reorder suggestions.
|
||||||
|
Future<List<ReorderItem>> getRecentReorders();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:krow_core/core.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
import '../repositories/home_repository_interface.dart';
|
||||||
|
|
||||||
|
/// Use case to fetch recent completed shift roles for reorder suggestions.
|
||||||
|
class GetRecentReordersUseCase implements NoInputUseCase<List<ReorderItem>> {
|
||||||
|
final HomeRepositoryInterface _repository;
|
||||||
|
|
||||||
|
/// Creates a [GetRecentReordersUseCase].
|
||||||
|
GetRecentReordersUseCase(this._repository);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ReorderItem>> call() {
|
||||||
|
return _repository.getRecentReorders();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import 'package:client_home/src/domain/repositories/home_repository_interface.da
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
import '../../domain/usecases/get_dashboard_data_usecase.dart';
|
import '../../domain/usecases/get_dashboard_data_usecase.dart';
|
||||||
|
import '../../domain/usecases/get_recent_reorders_usecase.dart';
|
||||||
import '../../domain/usecases/get_user_session_data_usecase.dart';
|
import '../../domain/usecases/get_user_session_data_usecase.dart';
|
||||||
import 'client_home_event.dart';
|
import 'client_home_event.dart';
|
||||||
import 'client_home_state.dart';
|
import 'client_home_state.dart';
|
||||||
@@ -9,12 +10,15 @@ import 'client_home_state.dart';
|
|||||||
/// BLoC responsible for managing the state and business logic of the client home dashboard.
|
/// BLoC responsible for managing the state and business logic of the client home dashboard.
|
||||||
class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
|
class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
|
||||||
final GetDashboardDataUseCase _getDashboardDataUseCase;
|
final GetDashboardDataUseCase _getDashboardDataUseCase;
|
||||||
|
final GetRecentReordersUseCase _getRecentReordersUseCase;
|
||||||
final GetUserSessionDataUseCase _getUserSessionDataUseCase;
|
final GetUserSessionDataUseCase _getUserSessionDataUseCase;
|
||||||
|
|
||||||
ClientHomeBloc({
|
ClientHomeBloc({
|
||||||
required GetDashboardDataUseCase getDashboardDataUseCase,
|
required GetDashboardDataUseCase getDashboardDataUseCase,
|
||||||
|
required GetRecentReordersUseCase getRecentReordersUseCase,
|
||||||
required GetUserSessionDataUseCase getUserSessionDataUseCase,
|
required GetUserSessionDataUseCase getUserSessionDataUseCase,
|
||||||
}) : _getDashboardDataUseCase = getDashboardDataUseCase,
|
}) : _getDashboardDataUseCase = getDashboardDataUseCase,
|
||||||
|
_getRecentReordersUseCase = getRecentReordersUseCase,
|
||||||
_getUserSessionDataUseCase = getUserSessionDataUseCase,
|
_getUserSessionDataUseCase = getUserSessionDataUseCase,
|
||||||
super(const ClientHomeState()) {
|
super(const ClientHomeState()) {
|
||||||
on<ClientHomeStarted>(_onStarted);
|
on<ClientHomeStarted>(_onStarted);
|
||||||
@@ -35,11 +39,13 @@ class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
|
|||||||
|
|
||||||
// Get dashboard data
|
// Get dashboard data
|
||||||
final HomeDashboardData data = await _getDashboardDataUseCase();
|
final HomeDashboardData data = await _getDashboardDataUseCase();
|
||||||
|
final List<ReorderItem> reorderItems = await _getRecentReordersUseCase();
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
status: ClientHomeStatus.success,
|
status: ClientHomeStatus.success,
|
||||||
dashboardData: data,
|
dashboardData: data,
|
||||||
|
reorderItems: reorderItems,
|
||||||
businessName: sessionData.businessName,
|
businessName: sessionData.businessName,
|
||||||
photoUrl: sessionData.photoUrl,
|
photoUrl: sessionData.photoUrl,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class ClientHomeState extends Equatable {
|
|||||||
final bool isEditMode;
|
final bool isEditMode;
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
final HomeDashboardData dashboardData;
|
final HomeDashboardData dashboardData;
|
||||||
|
final List<ReorderItem> reorderItems;
|
||||||
final String businessName;
|
final String businessName;
|
||||||
final String? photoUrl;
|
final String? photoUrl;
|
||||||
|
|
||||||
@@ -19,9 +20,11 @@ class ClientHomeState extends Equatable {
|
|||||||
this.status = ClientHomeStatus.initial,
|
this.status = ClientHomeStatus.initial,
|
||||||
this.widgetOrder = const <String>[
|
this.widgetOrder = const <String>[
|
||||||
'actions',
|
'actions',
|
||||||
|
'reorder',
|
||||||
],
|
],
|
||||||
this.widgetVisibility = const <String, bool>{
|
this.widgetVisibility = const <String, bool>{
|
||||||
'actions': true,
|
'actions': true,
|
||||||
|
'reorder': true,
|
||||||
},
|
},
|
||||||
this.isEditMode = false,
|
this.isEditMode = false,
|
||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
@@ -33,6 +36,7 @@ class ClientHomeState extends Equatable {
|
|||||||
totalNeeded: 10,
|
totalNeeded: 10,
|
||||||
totalFilled: 8,
|
totalFilled: 8,
|
||||||
),
|
),
|
||||||
|
this.reorderItems = const <ReorderItem>[],
|
||||||
this.businessName = 'Your Company',
|
this.businessName = 'Your Company',
|
||||||
this.photoUrl,
|
this.photoUrl,
|
||||||
});
|
});
|
||||||
@@ -44,6 +48,7 @@ class ClientHomeState extends Equatable {
|
|||||||
bool? isEditMode,
|
bool? isEditMode,
|
||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
HomeDashboardData? dashboardData,
|
HomeDashboardData? dashboardData,
|
||||||
|
List<ReorderItem>? reorderItems,
|
||||||
String? businessName,
|
String? businessName,
|
||||||
String? photoUrl,
|
String? photoUrl,
|
||||||
}) {
|
}) {
|
||||||
@@ -54,6 +59,7 @@ class ClientHomeState extends Equatable {
|
|||||||
isEditMode: isEditMode ?? this.isEditMode,
|
isEditMode: isEditMode ?? this.isEditMode,
|
||||||
errorMessage: errorMessage ?? this.errorMessage,
|
errorMessage: errorMessage ?? this.errorMessage,
|
||||||
dashboardData: dashboardData ?? this.dashboardData,
|
dashboardData: dashboardData ?? this.dashboardData,
|
||||||
|
reorderItems: reorderItems ?? this.reorderItems,
|
||||||
businessName: businessName ?? this.businessName,
|
businessName: businessName ?? this.businessName,
|
||||||
photoUrl: photoUrl ?? this.photoUrl,
|
photoUrl: photoUrl ?? this.photoUrl,
|
||||||
);
|
);
|
||||||
@@ -67,6 +73,7 @@ class ClientHomeState extends Equatable {
|
|||||||
isEditMode,
|
isEditMode,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
dashboardData,
|
dashboardData,
|
||||||
|
reorderItems,
|
||||||
businessName,
|
businessName,
|
||||||
photoUrl,
|
photoUrl,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
case 'reorder':
|
case 'reorder':
|
||||||
return ReorderWidget(
|
return ReorderWidget(
|
||||||
|
orders: state.reorderItems,
|
||||||
onReorderPressed: (Map<String, dynamic> data) {
|
onReorderPressed: (Map<String, dynamic> data) {
|
||||||
ClientHomeSheets.showOrderFormSheet(
|
ClientHomeSheets.showOrderFormSheet(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -1,46 +1,28 @@
|
|||||||
import 'package:core_localization/core_localization.dart';
|
import 'package:core_localization/core_localization.dart';
|
||||||
import 'package:design_system/design_system.dart';
|
import 'package:design_system/design_system.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
|
||||||
/// A widget that allows clients to reorder recent shifts.
|
/// A widget that allows clients to reorder recent shifts.
|
||||||
class ReorderWidget extends StatelessWidget {
|
class ReorderWidget extends StatelessWidget {
|
||||||
|
/// Recent completed orders for reorder.
|
||||||
|
final List<ReorderItem> orders;
|
||||||
|
|
||||||
/// Callback when a reorder button is pressed.
|
/// Callback when a reorder button is pressed.
|
||||||
final Function(Map<String, dynamic> shiftData) onReorderPressed;
|
final Function(Map<String, dynamic> shiftData) onReorderPressed;
|
||||||
|
|
||||||
/// Creates a [ReorderWidget].
|
/// Creates a [ReorderWidget].
|
||||||
const ReorderWidget({super.key, required this.onReorderPressed});
|
const ReorderWidget({
|
||||||
|
super.key,
|
||||||
|
required this.orders,
|
||||||
|
required this.onReorderPressed,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TranslationsClientHomeReorderEn i18n = t.client_home.reorder;
|
final TranslationsClientHomeReorderEn i18n = t.client_home.reorder;
|
||||||
|
|
||||||
// Mock recent orders
|
final List<ReorderItem> recentOrders = orders;
|
||||||
final List<Map<String, Object>> recentOrders = <Map<String, Object>>[
|
|
||||||
<String, Object>{
|
|
||||||
'title': 'Server',
|
|
||||||
'location': 'Downtown Restaurant',
|
|
||||||
'hourlyRate': 18.0,
|
|
||||||
'hours': 6,
|
|
||||||
'workers': 3,
|
|
||||||
'type': 'One Day',
|
|
||||||
},
|
|
||||||
<String, Object>{
|
|
||||||
'title': 'Bartender',
|
|
||||||
'location': 'Rooftop Bar',
|
|
||||||
'hourlyRate': 22.0,
|
|
||||||
'hours': 7,
|
|
||||||
'workers': 2,
|
|
||||||
'type': 'One Day',
|
|
||||||
},
|
|
||||||
<String, Object>{
|
|
||||||
'title': 'Event Staff',
|
|
||||||
'location': 'Convention Center',
|
|
||||||
'hourlyRate': 20.0,
|
|
||||||
'hours': 10,
|
|
||||||
'workers': 5,
|
|
||||||
'type': 'Multi-Day',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -60,11 +42,9 @@ class ReorderWidget extends StatelessWidget {
|
|||||||
separatorBuilder: (BuildContext context, int index) =>
|
separatorBuilder: (BuildContext context, int index) =>
|
||||||
const SizedBox(width: UiConstants.space3),
|
const SizedBox(width: UiConstants.space3),
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final Map<String, Object> order = recentOrders[index];
|
final ReorderItem order = recentOrders[index];
|
||||||
final double totalCost =
|
final double totalCost =
|
||||||
(order['hourlyRate'] as double) *
|
order.hourlyRate * order.hours * order.workers;
|
||||||
(order['hours'] as int) *
|
|
||||||
(order['workers'] as int);
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: 260,
|
width: 260,
|
||||||
@@ -110,12 +90,12 @@ class ReorderWidget extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
order['title'] as String,
|
order.title,
|
||||||
style: UiTypography.body2b,
|
style: UiTypography.body2b,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
order['location'] as String,
|
order.location,
|
||||||
style:
|
style:
|
||||||
UiTypography.footnote1r.textSecondary,
|
UiTypography.footnote1r.textSecondary,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -135,9 +115,9 @@ class ReorderWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
i18n.per_hr(
|
i18n.per_hr(
|
||||||
amount: order['hourlyRate'].toString(),
|
amount: order.hourlyRate.toString(),
|
||||||
) +
|
) +
|
||||||
' · ${order['hours']}h',
|
' · ${order.hours}h',
|
||||||
style: UiTypography.footnote2r.textSecondary,
|
style: UiTypography.footnote2r.textSecondary,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -149,7 +129,7 @@ class ReorderWidget extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_Badge(
|
_Badge(
|
||||||
icon: UiIcons.success,
|
icon: UiIcons.success,
|
||||||
text: order['type'] as String,
|
text: order.type,
|
||||||
color: const Color(0xFF2563EB),
|
color: const Color(0xFF2563EB),
|
||||||
bg: const Color(0xFF2563EB),
|
bg: const Color(0xFF2563EB),
|
||||||
textColor: UiColors.white,
|
textColor: UiColors.white,
|
||||||
@@ -157,7 +137,7 @@ class ReorderWidget extends StatelessWidget {
|
|||||||
const SizedBox(width: UiConstants.space2),
|
const SizedBox(width: UiConstants.space2),
|
||||||
_Badge(
|
_Badge(
|
||||||
icon: UiIcons.building,
|
icon: UiIcons.building,
|
||||||
text: '${order['workers']}',
|
text: '${order.workers}',
|
||||||
color: const Color(0xFF334155),
|
color: const Color(0xFF334155),
|
||||||
bg: const Color(0xFFF1F5F9),
|
bg: const Color(0xFFF1F5F9),
|
||||||
textColor: const Color(0xFF334155),
|
textColor: const Color(0xFF334155),
|
||||||
@@ -169,7 +149,15 @@ class ReorderWidget extends StatelessWidget {
|
|||||||
height: 28,
|
height: 28,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () => onReorderPressed(order),
|
onPressed: () => onReorderPressed(<String, dynamic>{
|
||||||
|
'orderId': order.orderId,
|
||||||
|
'title': order.title,
|
||||||
|
'location': order.location,
|
||||||
|
'hourlyRate': order.hourlyRate,
|
||||||
|
'hours': order.hours,
|
||||||
|
'workers': order.workers,
|
||||||
|
'type': order.type,
|
||||||
|
}),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: UiColors.primary,
|
backgroundColor: UiColors.primary,
|
||||||
foregroundColor: UiColors.white,
|
foregroundColor: UiColors.white,
|
||||||
|
|||||||
@@ -1,6 +1,27 @@
|
|||||||
import 'package:design_system/design_system.dart';
|
import 'package:design_system/design_system.dart';
|
||||||
|
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
|
|
||||||
|
class _RoleOption {
|
||||||
|
const _RoleOption({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VendorOption {
|
||||||
|
const _VendorOption({required this.id, required this.name});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
}
|
||||||
|
|
||||||
/// A bottom sheet form for creating or reordering shifts.
|
/// A bottom sheet form for creating or reordering shifts.
|
||||||
///
|
///
|
||||||
@@ -34,63 +55,18 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
|
|
||||||
late List<Map<String, dynamic>> _positions;
|
late List<Map<String, dynamic>> _positions;
|
||||||
|
|
||||||
final List<String> _roles = <String>[
|
final dc.ExampleConnector _dataConnect = dc.ExampleConnector.instance;
|
||||||
'Server',
|
List<_VendorOption> _vendors = const <_VendorOption>[];
|
||||||
'Bartender',
|
List<_RoleOption> _roles = const <_RoleOption>[];
|
||||||
'Cook',
|
|
||||||
'Busser',
|
|
||||||
'Host',
|
|
||||||
'Barista',
|
|
||||||
'Dishwasher',
|
|
||||||
'Event Staff',
|
|
||||||
'Warehouse Worker',
|
|
||||||
'Retail Associate',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Vendor options
|
|
||||||
final List<Map<String, dynamic>> _vendors = <Map<String, dynamic>>[
|
|
||||||
<String, dynamic>{
|
|
||||||
'id': 'v1',
|
|
||||||
'name': 'Elite Staffing',
|
|
||||||
'rates': <String, double>{
|
|
||||||
'Server': 25.0,
|
|
||||||
'Bartender': 30.0,
|
|
||||||
'Cook': 28.0,
|
|
||||||
'Busser': 18.0,
|
|
||||||
'Host': 20.0,
|
|
||||||
'Barista': 22.0,
|
|
||||||
'Dishwasher': 17.0,
|
|
||||||
'Event Staff': 19.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
<String, dynamic>{
|
|
||||||
'id': 'v2',
|
|
||||||
'name': 'Premier Workforce',
|
|
||||||
'rates': <String, double>{
|
|
||||||
'Server': 22.0,
|
|
||||||
'Bartender': 28.0,
|
|
||||||
'Cook': 25.0,
|
|
||||||
'Busser': 16.0,
|
|
||||||
'Host': 18.0,
|
|
||||||
'Barista': 20.0,
|
|
||||||
'Dishwasher': 15.0,
|
|
||||||
'Event Staff': 18.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
String? _selectedVendorId;
|
String? _selectedVendorId;
|
||||||
|
|
||||||
final List<int> _lunchBreakOptions = <int>[0, 30, 45, 60];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Initialize date controller
|
// Initialize date controller (always today for reorder sheet)
|
||||||
final DateTime tomorrow = DateTime.now().add(const Duration(days: 1));
|
final DateTime today = DateTime.now();
|
||||||
final String initialDate = widget.initialData?['date'] ??
|
final String initialDate = today.toIso8601String().split('T')[0];
|
||||||
tomorrow.toIso8601String().split('T')[0];
|
|
||||||
_dateController = TextEditingController(text: initialDate);
|
_dateController = TextEditingController(text: initialDate);
|
||||||
|
|
||||||
// Initialize location controller
|
// Initialize location controller
|
||||||
@@ -100,21 +76,27 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
'',
|
'',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize vendor selection
|
|
||||||
_selectedVendorId = _vendors.first['id'];
|
|
||||||
|
|
||||||
// Initialize positions
|
// Initialize positions
|
||||||
_positions = <Map<String, dynamic>>[
|
_positions = <Map<String, dynamic>>[
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'role': widget.initialData?['title'] ?? widget.initialData?['role'] ?? '',
|
'roleId': widget.initialData?['roleId'] ?? '',
|
||||||
'count': widget.initialData?['workersNeeded'] ?? widget.initialData?['workers_needed'] ?? 1,
|
'roleName': widget.initialData?['title'] ?? widget.initialData?['role'] ?? '',
|
||||||
'start_time': widget.initialData?['startTime'] ?? widget.initialData?['start_time'] ?? '09:00',
|
'count': widget.initialData?['workersNeeded'] ??
|
||||||
'end_time': widget.initialData?['endTime'] ?? widget.initialData?['end_time'] ?? '17:00',
|
widget.initialData?['workers_needed'] ??
|
||||||
'hourly_rate': widget.initialData?['hourlyRate']?.toDouble() ?? 18.0,
|
1,
|
||||||
'lunch_break': 0,
|
'start_time': widget.initialData?['startTime'] ??
|
||||||
|
widget.initialData?['start_time'] ??
|
||||||
|
'09:00',
|
||||||
|
'end_time': widget.initialData?['endTime'] ??
|
||||||
|
widget.initialData?['end_time'] ??
|
||||||
|
'17:00',
|
||||||
|
'lunch_break': 'NO_BREAK',
|
||||||
'location': null,
|
'location': null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
_loadVendors();
|
||||||
|
_loadOrderDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -127,12 +109,12 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
void _addPosition() {
|
void _addPosition() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_positions.add(<String, dynamic>{
|
_positions.add(<String, dynamic>{
|
||||||
'role': '',
|
'roleId': '',
|
||||||
|
'roleName': '',
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'start_time': '09:00',
|
'start_time': '09:00',
|
||||||
'end_time': '17:00',
|
'end_time': '17:00',
|
||||||
'hourly_rate': 18.0,
|
'lunch_break': 'NO_BREAK',
|
||||||
'lunch_break': 0,
|
|
||||||
'location': null,
|
'location': null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -162,14 +144,27 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
hours = endH - startH;
|
hours = endH - startH;
|
||||||
if (hours < 0) hours += 24;
|
if (hours < 0) hours += 24;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
final String roleId = pos['roleId']?.toString() ?? '';
|
||||||
final double rate = pos['hourly_rate'] ?? 18.0;
|
final double rate = _rateForRole(roleId);
|
||||||
total += hours * rate * (pos['count'] as int);
|
total += hours * rate * (pos['count'] as int);
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getShiftType() {
|
String _getShiftType() {
|
||||||
|
final String? type = widget.initialData?['type']?.toString();
|
||||||
|
if (type != null && type.isNotEmpty) {
|
||||||
|
switch (type) {
|
||||||
|
case 'PERMANENT':
|
||||||
|
return 'Long Term';
|
||||||
|
case 'RECURRING':
|
||||||
|
return 'Multi-Day';
|
||||||
|
case 'RAPID':
|
||||||
|
return 'Rapid';
|
||||||
|
case 'ONE_TIME':
|
||||||
|
return 'One-Time Order';
|
||||||
|
}
|
||||||
|
}
|
||||||
// Determine shift type based on initial data
|
// Determine shift type based on initial data
|
||||||
final dynamic initialData = widget.initialData;
|
final dynamic initialData = widget.initialData;
|
||||||
if (initialData != null) {
|
if (initialData != null) {
|
||||||
@@ -183,14 +178,304 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
return 'One-Time Order';
|
return 'One-Time Order';
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSubmit() {
|
Future<void> _handleSubmit() async {
|
||||||
final Map<String, dynamic> formData = <String, dynamic>{
|
await _submitNewOrder();
|
||||||
'date': _dateController.text,
|
}
|
||||||
'location': _globalLocationController.text,
|
|
||||||
'positions': _positions,
|
Future<void> _submitNewOrder() async {
|
||||||
'total_cost': _calculateTotalCost(),
|
final String? businessId = dc.ClientSessionStore.instance.session?.business?.id;
|
||||||
};
|
if (businessId == null || businessId.isEmpty) {
|
||||||
widget.onSubmit(formData);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateTime date = DateTime.parse(_dateController.text);
|
||||||
|
final fdc.Timestamp orderTimestamp = _toTimestamp(date);
|
||||||
|
final dc.OrderType orderType =
|
||||||
|
_orderTypeFromValue(widget.initialData?['type']?.toString());
|
||||||
|
|
||||||
|
final fdc.OperationResult<dc.CreateOrderData, dc.CreateOrderVariables>
|
||||||
|
orderResult = await _dataConnect
|
||||||
|
.createOrder(
|
||||||
|
businessId: businessId,
|
||||||
|
orderType: orderType,
|
||||||
|
)
|
||||||
|
.vendorId(_selectedVendorId)
|
||||||
|
.location(_globalLocationController.text)
|
||||||
|
.status(dc.OrderStatus.POSTED)
|
||||||
|
.date(orderTimestamp)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
final String? orderId = orderResult.data?.order_insert.id;
|
||||||
|
if (orderId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int workersNeeded = _positions.fold<int>(
|
||||||
|
0,
|
||||||
|
(int sum, Map<String, dynamic> pos) => sum + (pos['count'] as int),
|
||||||
|
);
|
||||||
|
final String shiftTitle =
|
||||||
|
'Shift 1 ${DateFormat('yyyy-MM-dd').format(date)}';
|
||||||
|
final double shiftCost = _calculateTotalCost();
|
||||||
|
|
||||||
|
final fdc.OperationResult<dc.CreateShiftData, dc.CreateShiftVariables>
|
||||||
|
shiftResult = await _dataConnect
|
||||||
|
.createShift(title: shiftTitle, orderId: orderId)
|
||||||
|
.date(orderTimestamp)
|
||||||
|
.location(_globalLocationController.text)
|
||||||
|
.locationAddress(_globalLocationController.text)
|
||||||
|
.status(dc.ShiftStatus.PENDING)
|
||||||
|
.workersNeeded(workersNeeded)
|
||||||
|
.filled(0)
|
||||||
|
.durationDays(1)
|
||||||
|
.cost(shiftCost)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
final String? shiftId = shiftResult.data?.shift_insert.id;
|
||||||
|
if (shiftId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Map<String, dynamic> pos in _positions) {
|
||||||
|
final String roleId = pos['roleId']?.toString() ?? '';
|
||||||
|
if (roleId.isEmpty) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final DateTime start = _parseTime(date, pos['start_time'].toString());
|
||||||
|
final DateTime end = _parseTime(date, pos['end_time'].toString());
|
||||||
|
final DateTime normalizedEnd =
|
||||||
|
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||||
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
|
final int count = pos['count'] as int;
|
||||||
|
final double rate = _rateForRole(roleId);
|
||||||
|
final double totalValue = rate * hours * count;
|
||||||
|
final String lunchBreak = pos['lunch_break'] as String;
|
||||||
|
|
||||||
|
await _dataConnect
|
||||||
|
.createShiftRole(
|
||||||
|
shiftId: shiftId,
|
||||||
|
roleId: roleId,
|
||||||
|
count: count,
|
||||||
|
)
|
||||||
|
.startTime(_toTimestamp(start))
|
||||||
|
.endTime(_toTimestamp(normalizedEnd))
|
||||||
|
.hours(hours)
|
||||||
|
.breakType(_breakDurationFromValue(lunchBreak))
|
||||||
|
.totalValue(totalValue)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _dataConnect
|
||||||
|
.updateOrder(id: orderId)
|
||||||
|
.shifts(fdc.AnyValue(<String>[shiftId]))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
widget.onSubmit(<String, dynamic>{
|
||||||
|
'orderId': orderId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadVendors() async {
|
||||||
|
try {
|
||||||
|
final fdc.QueryResult<dc.ListVendorsData, void> result =
|
||||||
|
await _dataConnect.listVendors().execute();
|
||||||
|
final List<_VendorOption> vendors = result.data.vendors
|
||||||
|
.map(
|
||||||
|
(dc.ListVendorsVendors vendor) =>
|
||||||
|
_VendorOption(id: vendor.id, name: vendor.companyName),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_vendors = vendors;
|
||||||
|
final String? current = _selectedVendorId;
|
||||||
|
if (current == null ||
|
||||||
|
!vendors.any((_VendorOption v) => v.id == current)) {
|
||||||
|
_selectedVendorId = vendors.isNotEmpty ? vendors.first.id : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (_selectedVendorId != null) {
|
||||||
|
await _loadRolesForVendor(_selectedVendorId!);
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_vendors = const <_VendorOption>[];
|
||||||
|
_roles = const <_RoleOption>[];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadRolesForVendor(String vendorId) async {
|
||||||
|
try {
|
||||||
|
final fdc.QueryResult<dc.ListRolesByVendorIdData, dc.ListRolesByVendorIdVariables>
|
||||||
|
result =
|
||||||
|
await _dataConnect.listRolesByVendorId(vendorId: vendorId).execute();
|
||||||
|
final List<_RoleOption> roles = result.data.roles
|
||||||
|
.map(
|
||||||
|
(dc.ListRolesByVendorIdRoles role) => _RoleOption(
|
||||||
|
id: role.id,
|
||||||
|
name: role.name,
|
||||||
|
costPerHour: role.costPerHour,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() => _roles = roles);
|
||||||
|
} catch (_) {
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() => _roles = const <_RoleOption>[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadOrderDetails() async {
|
||||||
|
final String? orderId = widget.initialData?['orderId']?.toString();
|
||||||
|
if (orderId == null || orderId.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String? businessId = dc.ClientSessionStore.instance.session?.business?.id;
|
||||||
|
if (businessId == null || businessId.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final fdc.QueryResult<
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderData,
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderVariables> result = await _dataConnect
|
||||||
|
.listShiftRolesByBusinessAndOrder(
|
||||||
|
businessId: businessId,
|
||||||
|
orderId: orderId,
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
final List<dc.ListShiftRolesByBusinessAndOrderShiftRoles> shiftRoles =
|
||||||
|
result.data.shiftRoles;
|
||||||
|
if (shiftRoles.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShift firstShift =
|
||||||
|
shiftRoles.first.shift;
|
||||||
|
_globalLocationController.text = firstShift.order.location ??
|
||||||
|
firstShift.locationAddress ??
|
||||||
|
firstShift.location ??
|
||||||
|
_globalLocationController.text;
|
||||||
|
|
||||||
|
final String? vendorId = firstShift.order.vendorId;
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_selectedVendorId = vendorId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (vendorId != null && vendorId.isNotEmpty) {
|
||||||
|
await _loadRolesForVendor(vendorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Map<String, dynamic>> positions =
|
||||||
|
shiftRoles.map((dc.ListShiftRolesByBusinessAndOrderShiftRoles role) {
|
||||||
|
return <String, dynamic>{
|
||||||
|
'roleId': role.roleId,
|
||||||
|
'roleName': role.role.name,
|
||||||
|
'count': role.count,
|
||||||
|
'start_time': _formatTimeForField(role.startTime),
|
||||||
|
'end_time': _formatTimeForField(role.endTime),
|
||||||
|
'lunch_break': _breakValueFromDuration(role.breakType),
|
||||||
|
'location': null,
|
||||||
|
};
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_positions = positions;
|
||||||
|
});
|
||||||
|
} catch (_) {
|
||||||
|
// Keep defaults on failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatTimeForField(fdc.Timestamp? value) {
|
||||||
|
if (value == null) return '';
|
||||||
|
try {
|
||||||
|
return DateFormat('HH:mm').format(value.toDateTime());
|
||||||
|
} catch (_) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _breakValueFromDuration(dc.EnumValue<dc.BreakDuration>? breakType) {
|
||||||
|
final dc.BreakDuration? value =
|
||||||
|
breakType is dc.Known<dc.BreakDuration> ? breakType.value : null;
|
||||||
|
switch (value) {
|
||||||
|
case dc.BreakDuration.MIN_15:
|
||||||
|
return 'MIN_15';
|
||||||
|
case dc.BreakDuration.MIN_30:
|
||||||
|
return 'MIN_30';
|
||||||
|
case dc.BreakDuration.NO_BREAK:
|
||||||
|
case null:
|
||||||
|
return 'NO_BREAK';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.BreakDuration _breakDurationFromValue(String value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'MIN_15':
|
||||||
|
return dc.BreakDuration.MIN_15;
|
||||||
|
case 'MIN_30':
|
||||||
|
return dc.BreakDuration.MIN_30;
|
||||||
|
default:
|
||||||
|
return dc.BreakDuration.NO_BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.OrderType _orderTypeFromValue(String? value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'PERMANENT':
|
||||||
|
return dc.OrderType.PERMANENT;
|
||||||
|
case 'RECURRING':
|
||||||
|
return dc.OrderType.RECURRING;
|
||||||
|
case 'RAPID':
|
||||||
|
return dc.OrderType.RAPID;
|
||||||
|
case 'ONE_TIME':
|
||||||
|
default:
|
||||||
|
return dc.OrderType.ONE_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_RoleOption? _roleById(String roleId) {
|
||||||
|
for (final _RoleOption role in _roles) {
|
||||||
|
if (role.id == roleId) {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _rateForRole(String roleId) {
|
||||||
|
return _roleById(roleId)?.costPerHour ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime _parseTime(DateTime date, String time) {
|
||||||
|
DateTime parsed;
|
||||||
|
try {
|
||||||
|
parsed = DateFormat.Hm().parse(time);
|
||||||
|
} catch (_) {
|
||||||
|
parsed = DateFormat.jm().parse(time);
|
||||||
|
}
|
||||||
|
return DateTime(
|
||||||
|
date.year,
|
||||||
|
date.month,
|
||||||
|
date.day,
|
||||||
|
parsed.hour,
|
||||||
|
parsed.minute,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdc.Timestamp _toTimestamp(DateTime date) {
|
||||||
|
final int millis = date.millisecondsSinceEpoch;
|
||||||
|
final int seconds = millis ~/ 1000;
|
||||||
|
final int nanos = (millis % 1000) * 1000000;
|
||||||
|
return fdc.Timestamp(nanos, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -425,19 +710,18 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
color: UiColors.iconSecondary,
|
color: UiColors.iconSecondary,
|
||||||
),
|
),
|
||||||
style: UiTypography.body2r.textPrimary,
|
style: UiTypography.body2r.textPrimary,
|
||||||
items: _vendors
|
items: _vendors.map((_VendorOption vendor) {
|
||||||
.map(
|
return DropdownMenuItem<String>(
|
||||||
(Map<String, dynamic> vendor) => DropdownMenuItem<String>(
|
value: vendor.id,
|
||||||
value: vendor['id'],
|
child: Text(vendor.name),
|
||||||
child: Text(vendor['name']),
|
);
|
||||||
),
|
}).toList(),
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedVendorId = newValue;
|
_selectedVendorId = newValue;
|
||||||
});
|
});
|
||||||
|
_loadRolesForVendor(newValue);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -561,19 +845,32 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
|
|
||||||
_buildDropdownField(
|
_buildDropdownField(
|
||||||
hint: 'Select role',
|
hint: 'Select role',
|
||||||
value: pos['role'],
|
value: pos['roleId'],
|
||||||
items: _roles,
|
items: <String>[
|
||||||
itemBuilder: (dynamic role) {
|
..._roles.map((_RoleOption role) => role.id),
|
||||||
final Map<String, dynamic>? vendor = _vendors.firstWhere(
|
if (pos['roleId'] != null &&
|
||||||
(Map<String, dynamic> v) => v['id'] == _selectedVendorId,
|
pos['roleId'].toString().isNotEmpty &&
|
||||||
orElse: () => _vendors.first,
|
!_roles.any(
|
||||||
);
|
(_RoleOption role) => role.id == pos['roleId'].toString(),
|
||||||
final Map<String, dynamic>? rates = vendor?['rates'] as Map<String, dynamic>?;
|
))
|
||||||
final double? rate = rates?[role];
|
pos['roleId'].toString(),
|
||||||
if (rate == null) return role.toString();
|
],
|
||||||
return '$role - \$${rate.toStringAsFixed(0)}/hr';
|
itemBuilder: (dynamic roleId) {
|
||||||
|
final _RoleOption? role = _roleById(roleId.toString());
|
||||||
|
if (role == null) {
|
||||||
|
final String fallback = pos['roleName']?.toString() ?? '';
|
||||||
|
return fallback.isEmpty ? roleId.toString() : fallback;
|
||||||
|
}
|
||||||
|
return '${role.name} - \$${role.costPerHour.toStringAsFixed(0)}/hr';
|
||||||
|
},
|
||||||
|
onChanged: (dynamic val) {
|
||||||
|
final String roleId = val?.toString() ?? '';
|
||||||
|
final _RoleOption? role = _roleById(roleId);
|
||||||
|
setState(() {
|
||||||
|
_positions[index]['roleId'] = roleId;
|
||||||
|
_positions[index]['roleName'] = role?.name ?? '';
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onChanged: (dynamic val) => _updatePosition(index, 'role', val),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: UiConstants.space3),
|
const SizedBox(height: UiConstants.space3),
|
||||||
@@ -592,10 +889,16 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
|
|||||||
_buildDropdownField(
|
_buildDropdownField(
|
||||||
hint: 'None',
|
hint: 'None',
|
||||||
value: pos['lunch_break'],
|
value: pos['lunch_break'],
|
||||||
items: _lunchBreakOptions,
|
items: <String>['NO_BREAK', 'MIN_15', 'MIN_30'],
|
||||||
itemBuilder: (dynamic minutes) {
|
itemBuilder: (dynamic value) {
|
||||||
if (minutes == 0) return 'None';
|
switch (value.toString()) {
|
||||||
return '$minutes min';
|
case 'MIN_15':
|
||||||
|
return '15 min';
|
||||||
|
case 'MIN_30':
|
||||||
|
return '30 min';
|
||||||
|
default:
|
||||||
|
return 'No Break';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onChanged: (dynamic val) => _updatePosition(index, 'lunch_break', val),
|
onChanged: (dynamic val) => _updatePosition(index, 'lunch_break', val),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -42,11 +42,6 @@ class ViewOrdersRepositoryImpl implements IViewOrdersRepository {
|
|||||||
'Your Company';
|
'Your Company';
|
||||||
|
|
||||||
return result.data.shiftRoles.map((dc.ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole) {
|
return result.data.shiftRoles.map((dc.ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole) {
|
||||||
print(
|
|
||||||
'ViewOrders shiftRole: shiftId=${shiftRole.shiftId} roleId=${shiftRole.roleId} '
|
|
||||||
'startTime=${shiftRole.startTime?.toJson()} endTime=${shiftRole.endTime?.toJson()} '
|
|
||||||
'hours=${shiftRole.hours} totalValue=${shiftRole.totalValue}',
|
|
||||||
);
|
|
||||||
final DateTime? shiftDate = shiftRole.shift.date?.toDateTime();
|
final DateTime? shiftDate = shiftRole.shift.date?.toDateTime();
|
||||||
final String dateStr = shiftDate == null
|
final String dateStr = shiftDate == null
|
||||||
? ''
|
? ''
|
||||||
@@ -58,10 +53,18 @@ class ViewOrdersRepositoryImpl implements IViewOrdersRepository {
|
|||||||
final double hours = shiftRole.hours ?? 0;
|
final double hours = shiftRole.hours ?? 0;
|
||||||
final double totalValue = shiftRole.totalValue ?? 0;
|
final double totalValue = shiftRole.totalValue ?? 0;
|
||||||
final double hourlyRate = _hourlyRate(shiftRole.totalValue, shiftRole.hours);
|
final double hourlyRate = _hourlyRate(shiftRole.totalValue, shiftRole.hours);
|
||||||
final String status = filled >= workersNeeded ? 'filled' : 'open';
|
// final String status = filled >= workersNeeded ? 'filled' : 'open';
|
||||||
|
final String status = shiftRole.shift.status?.stringValue ?? 'OPEN';
|
||||||
|
|
||||||
|
print(
|
||||||
|
'ViewOrders item: date=$dateStr status=$status shiftId=${shiftRole.shiftId} '
|
||||||
|
'roleId=${shiftRole.roleId} start=${shiftRole.startTime?.toJson()} '
|
||||||
|
'end=${shiftRole.endTime?.toJson()} hours=$hours totalValue=$totalValue',
|
||||||
|
);
|
||||||
|
|
||||||
return domain.OrderItem(
|
return domain.OrderItem(
|
||||||
id: _shiftRoleKey(shiftRole.shiftId, shiftRole.roleId),
|
id: _shiftRoleKey(shiftRole.shiftId, shiftRole.roleId),
|
||||||
|
orderId: shiftRole.shift.order.id,
|
||||||
title: '${shiftRole.role.name} - ${shiftRole.shift.title}',
|
title: '${shiftRole.role.name} - ${shiftRole.shift.title}',
|
||||||
clientName: businessName,
|
clientName: businessName,
|
||||||
status: status,
|
status: status,
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ class ViewOrdersCubit extends Cubit<ViewOrdersState> {
|
|||||||
filled >= order.workersNeeded ? 'filled' : order.status;
|
filled >= order.workersNeeded ? 'filled' : order.status;
|
||||||
return OrderItem(
|
return OrderItem(
|
||||||
id: order.id,
|
id: order.id,
|
||||||
|
orderId: order.orderId,
|
||||||
title: order.title,
|
title: order.title,
|
||||||
clientName: order.clientName,
|
clientName: order.clientName,
|
||||||
status: status,
|
status: status,
|
||||||
@@ -191,16 +192,18 @@ class ViewOrdersCubit extends Cubit<ViewOrdersState> {
|
|||||||
return ordersOnDate
|
return ordersOnDate
|
||||||
.where(
|
.where(
|
||||||
(OrderItem s) =>
|
(OrderItem s) =>
|
||||||
<String>['open', 'filled', 'confirmed'].contains(s.status),
|
// TODO(orders): move PENDING to its own tab once available.
|
||||||
|
<String>['OPEN', 'FILLED', 'CONFIRMED', 'PENDING']
|
||||||
|
.contains(s.status),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
} else if (state.filterTab == 'active') {
|
} else if (state.filterTab == 'active') {
|
||||||
return ordersOnDate
|
return ordersOnDate
|
||||||
.where((OrderItem s) => s.status == 'in_progress')
|
.where((OrderItem s) => s.status == 'IN_PROGRESS')
|
||||||
.toList();
|
.toList();
|
||||||
} else if (state.filterTab == 'completed') {
|
} else if (state.filterTab == 'completed') {
|
||||||
return ordersOnDate
|
return ordersOnDate
|
||||||
.where((OrderItem s) => s.status == 'completed')
|
.where((OrderItem s) => s.status == 'COMPLETED')
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
return <OrderItem>[];
|
return <OrderItem>[];
|
||||||
@@ -217,11 +220,11 @@ class ViewOrdersCubit extends Cubit<ViewOrdersState> {
|
|||||||
|
|
||||||
if (category == 'active') {
|
if (category == 'active') {
|
||||||
return ordersOnDate
|
return ordersOnDate
|
||||||
.where((OrderItem s) => s.status == 'in_progress')
|
.where((OrderItem s) => s.status == 'IN_PROGRESS')
|
||||||
.length;
|
.length;
|
||||||
} else if (category == 'completed') {
|
} else if (category == 'completed') {
|
||||||
return ordersOnDate
|
return ordersOnDate
|
||||||
.where((OrderItem s) => s.status == 'completed')
|
.where((OrderItem s) => s.status == 'COMPLETED')
|
||||||
.length;
|
.length;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -238,7 +241,9 @@ class ViewOrdersCubit extends Cubit<ViewOrdersState> {
|
|||||||
return ordersOnDate
|
return ordersOnDate
|
||||||
.where(
|
.where(
|
||||||
(OrderItem s) =>
|
(OrderItem s) =>
|
||||||
<String>['open', 'filled', 'confirmed'].contains(s.status),
|
// TODO(orders): move PENDING to its own tab once available.
|
||||||
|
<String>['OPEN', 'FILLED', 'CONFIRMED', 'PENDING']
|
||||||
|
.contains(s.status),
|
||||||
)
|
)
|
||||||
.length;
|
.length;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import 'package:core_localization/core_localization.dart';
|
import 'package:core_localization/core_localization.dart';
|
||||||
import 'package:design_system/design_system.dart';
|
import 'package:design_system/design_system.dart';
|
||||||
|
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
||||||
|
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
|
||||||
/// A rich card displaying details of a client order/shift.
|
/// A rich card displaying details of a client order/shift.
|
||||||
@@ -34,16 +37,16 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
|||||||
/// Returns the semantic color for the given status.
|
/// Returns the semantic color for the given status.
|
||||||
Color _getStatusColor({required String status}) {
|
Color _getStatusColor({required String status}) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'open':
|
case 'OPEN':
|
||||||
return UiColors.primary;
|
return UiColors.primary;
|
||||||
case 'filled':
|
case 'FILLED':
|
||||||
case 'confirmed':
|
case 'CONFIRMED':
|
||||||
return UiColors.textSuccess;
|
return UiColors.textSuccess;
|
||||||
case 'in_progress':
|
case 'IN_PROGRESS':
|
||||||
return UiColors.textWarning;
|
return UiColors.textWarning;
|
||||||
case 'completed':
|
case 'COMPLETED':
|
||||||
return UiColors.primary;
|
return UiColors.primary;
|
||||||
case 'cancelled':
|
case 'CANCELED':
|
||||||
return UiColors.destructive;
|
return UiColors.destructive;
|
||||||
default:
|
default:
|
||||||
return UiColors.textSecondary;
|
return UiColors.textSecondary;
|
||||||
@@ -53,17 +56,17 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
|||||||
/// Returns the localized label for the given status.
|
/// Returns the localized label for the given status.
|
||||||
String _getStatusLabel({required String status}) {
|
String _getStatusLabel({required String status}) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'open':
|
case 'OPEN':
|
||||||
return t.client_view_orders.card.open;
|
return t.client_view_orders.card.open;
|
||||||
case 'filled':
|
case 'FILLED':
|
||||||
return t.client_view_orders.card.filled;
|
return t.client_view_orders.card.filled;
|
||||||
case 'confirmed':
|
case 'CONFIRMED':
|
||||||
return t.client_view_orders.card.confirmed;
|
return t.client_view_orders.card.confirmed;
|
||||||
case 'in_progress':
|
case 'IN_PROGRESS':
|
||||||
return t.client_view_orders.card.in_progress;
|
return t.client_view_orders.card.in_progress;
|
||||||
case 'completed':
|
case 'COMPLETED':
|
||||||
return t.client_view_orders.card.completed;
|
return t.client_view_orders.card.completed;
|
||||||
case 'cancelled':
|
case 'CANCELED':
|
||||||
return t.client_view_orders.card.cancelled;
|
return t.client_view_orders.card.cancelled;
|
||||||
default:
|
default:
|
||||||
return status.toUpperCase();
|
return status.toUpperCase();
|
||||||
@@ -619,6 +622,25 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _RoleOption {
|
||||||
|
const _RoleOption({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ShiftRoleKey {
|
||||||
|
const _ShiftRoleKey({required this.shiftId, required this.roleId});
|
||||||
|
|
||||||
|
final String shiftId;
|
||||||
|
final String roleId;
|
||||||
|
}
|
||||||
|
|
||||||
/// A sophisticated bottom sheet for editing an existing order,
|
/// A sophisticated bottom sheet for editing an existing order,
|
||||||
/// following the Unified Order Flow prototype and matching OneTimeOrderView.
|
/// following the Unified Order Flow prototype and matching OneTimeOrderView.
|
||||||
class _OrderEditSheet extends StatefulWidget {
|
class _OrderEditSheet extends StatefulWidget {
|
||||||
@@ -639,8 +661,15 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
|
|
||||||
late List<Map<String, dynamic>> _positions;
|
late List<Map<String, dynamic>> _positions;
|
||||||
|
|
||||||
|
final dc.ExampleConnector _dataConnect = dc.ExampleConnector.instance;
|
||||||
|
final firebase.FirebaseAuth _firebaseAuth = firebase.FirebaseAuth.instance;
|
||||||
|
|
||||||
List<Vendor> _vendors = const <Vendor>[];
|
List<Vendor> _vendors = const <Vendor>[];
|
||||||
Vendor? _selectedVendor;
|
Vendor? _selectedVendor;
|
||||||
|
List<_RoleOption> _roles = const <_RoleOption>[];
|
||||||
|
|
||||||
|
String? _shiftId;
|
||||||
|
List<_ShiftRoleKey> _originalShiftRoles = const <_ShiftRoleKey>[];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -652,47 +681,19 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
|
|
||||||
_positions = <Map<String, dynamic>>[
|
_positions = <Map<String, dynamic>>[
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'role': widget.order.title,
|
'shiftId': null,
|
||||||
|
'roleId': '',
|
||||||
|
'roleName': '',
|
||||||
|
'originalRoleId': null,
|
||||||
'count': widget.order.workersNeeded,
|
'count': widget.order.workersNeeded,
|
||||||
'start_time': widget.order.startTime,
|
'start_time': widget.order.startTime,
|
||||||
'end_time': widget.order.endTime,
|
'end_time': widget.order.endTime,
|
||||||
'lunch_break': 0,
|
'lunch_break': 'NO_BREAK',
|
||||||
'location': null,
|
'location': null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Mock vendors initialization
|
_loadOrderDetails();
|
||||||
_vendors = const <Vendor>[
|
|
||||||
Vendor(
|
|
||||||
id: 'v1',
|
|
||||||
name: 'Elite Staffing',
|
|
||||||
rates: <String, double>{
|
|
||||||
'Server': 25.0,
|
|
||||||
'Bartender': 30.0,
|
|
||||||
'Cook': 28.0,
|
|
||||||
'Busser': 18.0,
|
|
||||||
'Host': 20.0,
|
|
||||||
'Barista': 22.0,
|
|
||||||
'Dishwasher': 17.0,
|
|
||||||
'Event Staff': 19.0,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Vendor(
|
|
||||||
id: 'v2',
|
|
||||||
name: 'Premier Workforce',
|
|
||||||
rates: <String, double>{
|
|
||||||
'Server': 22.0,
|
|
||||||
'Bartender': 28.0,
|
|
||||||
'Cook': 25.0,
|
|
||||||
'Busser': 16.0,
|
|
||||||
'Host': 18.0,
|
|
||||||
'Barista': 20.0,
|
|
||||||
'Dishwasher': 15.0,
|
|
||||||
'Event Staff': 18.0,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
];
|
|
||||||
_selectedVendor = _vendors.first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -702,16 +703,396 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _loadOrderDetails() async {
|
||||||
|
final String? businessId =
|
||||||
|
dc.ClientSessionStore.instance.session?.business?.id;
|
||||||
|
if (businessId == null || businessId.isEmpty) {
|
||||||
|
await _firebaseAuth.signOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.order.orderId.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final QueryResult<
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderData,
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderVariables> result = await _dataConnect
|
||||||
|
.listShiftRolesByBusinessAndOrder(
|
||||||
|
businessId: businessId,
|
||||||
|
orderId: widget.order.orderId,
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
final List<dc.ListShiftRolesByBusinessAndOrderShiftRoles> shiftRoles =
|
||||||
|
result.data.shiftRoles;
|
||||||
|
if (shiftRoles.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShift firstShift =
|
||||||
|
shiftRoles.first.shift;
|
||||||
|
final DateTime? orderDate = firstShift.order.date?.toDateTime();
|
||||||
|
final String dateText = orderDate == null
|
||||||
|
? widget.order.date
|
||||||
|
: DateFormat('yyyy-MM-dd').format(orderDate);
|
||||||
|
final String location = firstShift.order.location ??
|
||||||
|
firstShift.locationAddress ??
|
||||||
|
firstShift.location ??
|
||||||
|
widget.order.locationAddress;
|
||||||
|
|
||||||
|
_dateController.text = dateText;
|
||||||
|
_globalLocationController.text = location;
|
||||||
|
_shiftId = shiftRoles.first.shiftId;
|
||||||
|
|
||||||
|
final List<Map<String, dynamic>> positions =
|
||||||
|
shiftRoles.map((dc.ListShiftRolesByBusinessAndOrderShiftRoles role) {
|
||||||
|
return <String, dynamic>{
|
||||||
|
'shiftId': role.shiftId,
|
||||||
|
'roleId': role.roleId,
|
||||||
|
'roleName': role.role.name,
|
||||||
|
'originalRoleId': role.roleId,
|
||||||
|
'count': role.count,
|
||||||
|
'start_time': _formatTimeForField(role.startTime),
|
||||||
|
'end_time': _formatTimeForField(role.endTime),
|
||||||
|
'lunch_break': _breakValueFromDuration(role.breakType),
|
||||||
|
'location': null,
|
||||||
|
};
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
if (positions.isEmpty) {
|
||||||
|
positions.add(_emptyPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<_ShiftRoleKey> originalShiftRoles =
|
||||||
|
shiftRoles
|
||||||
|
.map(
|
||||||
|
(dc.ListShiftRolesByBusinessAndOrderShiftRoles role) =>
|
||||||
|
_ShiftRoleKey(shiftId: role.shiftId, roleId: role.roleId),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
await _loadVendorsAndSelect(firstShift.order.vendorId);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_positions = positions;
|
||||||
|
_originalShiftRoles = originalShiftRoles;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Keep current state on failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadVendorsAndSelect(String? selectedVendorId) async {
|
||||||
|
try {
|
||||||
|
final QueryResult<dc.ListVendorsData, void> result =
|
||||||
|
await _dataConnect.listVendors().execute();
|
||||||
|
final List<Vendor> vendors = result.data.vendors
|
||||||
|
.map(
|
||||||
|
(dc.ListVendorsVendors vendor) => Vendor(
|
||||||
|
id: vendor.id,
|
||||||
|
name: vendor.companyName,
|
||||||
|
rates: const <String, double>{},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Vendor? selectedVendor;
|
||||||
|
if (selectedVendorId != null && selectedVendorId.isNotEmpty) {
|
||||||
|
for (final Vendor vendor in vendors) {
|
||||||
|
if (vendor.id == selectedVendorId) {
|
||||||
|
selectedVendor = vendor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectedVendor ??= vendors.isNotEmpty ? vendors.first : null;
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_vendors = vendors;
|
||||||
|
_selectedVendor = selectedVendor;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedVendor != null) {
|
||||||
|
await _loadRolesForVendor(selectedVendor.id);
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_vendors = const <Vendor>[];
|
||||||
|
_selectedVendor = null;
|
||||||
|
_roles = const <_RoleOption>[];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadRolesForVendor(String vendorId) async {
|
||||||
|
try {
|
||||||
|
final QueryResult<dc.ListRolesByVendorIdData, dc.ListRolesByVendorIdVariables>
|
||||||
|
result = await _dataConnect
|
||||||
|
.listRolesByVendorId(vendorId: vendorId)
|
||||||
|
.execute();
|
||||||
|
final List<_RoleOption> roles = result.data.roles
|
||||||
|
.map(
|
||||||
|
(dc.ListRolesByVendorIdRoles role) => _RoleOption(
|
||||||
|
id: role.id,
|
||||||
|
name: role.name,
|
||||||
|
costPerHour: role.costPerHour,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
if (mounted) {
|
||||||
|
setState(() => _roles = roles);
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() => _roles = const <_RoleOption>[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> _emptyPosition() {
|
||||||
|
return <String, dynamic>{
|
||||||
|
'shiftId': _shiftId,
|
||||||
|
'roleId': '',
|
||||||
|
'roleName': '',
|
||||||
|
'originalRoleId': null,
|
||||||
|
'count': 1,
|
||||||
|
'start_time': '09:00',
|
||||||
|
'end_time': '17:00',
|
||||||
|
'lunch_break': 'NO_BREAK',
|
||||||
|
'location': null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatTimeForField(Timestamp? value) {
|
||||||
|
if (value == null) return '';
|
||||||
|
try {
|
||||||
|
return DateFormat('HH:mm').format(value.toDateTime());
|
||||||
|
} catch (_) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _breakValueFromDuration(dc.EnumValue<dc.BreakDuration>? breakType) {
|
||||||
|
final dc.BreakDuration? value =
|
||||||
|
breakType is dc.Known<dc.BreakDuration> ? breakType.value : null;
|
||||||
|
switch (value) {
|
||||||
|
case dc.BreakDuration.MIN_15:
|
||||||
|
return 'MIN_15';
|
||||||
|
case dc.BreakDuration.MIN_30:
|
||||||
|
return 'MIN_30';
|
||||||
|
case dc.BreakDuration.NO_BREAK:
|
||||||
|
case null:
|
||||||
|
return 'NO_BREAK';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.BreakDuration _breakDurationFromValue(String value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'MIN_15':
|
||||||
|
return dc.BreakDuration.MIN_15;
|
||||||
|
case 'MIN_30':
|
||||||
|
return dc.BreakDuration.MIN_30;
|
||||||
|
default:
|
||||||
|
return dc.BreakDuration.NO_BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_RoleOption? _roleById(String roleId) {
|
||||||
|
for (final _RoleOption role in _roles) {
|
||||||
|
if (role.id == roleId) {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _rateForRole(String roleId) {
|
||||||
|
return _roleById(roleId)?.costPerHour ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime _parseDate(String value) {
|
||||||
|
try {
|
||||||
|
return DateFormat('yyyy-MM-dd').parse(value);
|
||||||
|
} catch (_) {
|
||||||
|
return DateTime.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime _parseTime(DateTime date, String time) {
|
||||||
|
if (time.trim().isEmpty) {
|
||||||
|
throw Exception('Shift time is missing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime parsed;
|
||||||
|
try {
|
||||||
|
parsed = DateFormat.Hm().parse(time);
|
||||||
|
} catch (_) {
|
||||||
|
parsed = DateFormat.jm().parse(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateTime(
|
||||||
|
date.year,
|
||||||
|
date.month,
|
||||||
|
date.day,
|
||||||
|
parsed.hour,
|
||||||
|
parsed.minute,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Timestamp _toTimestamp(DateTime date) {
|
||||||
|
final int millis = date.millisecondsSinceEpoch;
|
||||||
|
final int seconds = millis ~/ 1000;
|
||||||
|
final int nanos = (millis % 1000) * 1000000;
|
||||||
|
return Timestamp(nanos, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
double _calculateTotalCost() {
|
||||||
|
double total = 0;
|
||||||
|
for (final Map<String, dynamic> pos in _positions) {
|
||||||
|
final String roleId = pos['roleId']?.toString() ?? '';
|
||||||
|
if (roleId.isEmpty) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final DateTime date = _parseDate(_dateController.text);
|
||||||
|
final DateTime start = _parseTime(date, pos['start_time'].toString());
|
||||||
|
final DateTime end = _parseTime(date, pos['end_time'].toString());
|
||||||
|
final DateTime normalizedEnd =
|
||||||
|
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||||
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
|
final double rate = _rateForRole(roleId);
|
||||||
|
final int count = pos['count'] as int;
|
||||||
|
total += rate * hours * count;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _saveOrderChanges() async {
|
||||||
|
if (_shiftId == null || _shiftId!.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String? businessId =
|
||||||
|
dc.ClientSessionStore.instance.session?.business?.id;
|
||||||
|
if (businessId == null || businessId.isEmpty) {
|
||||||
|
await _firebaseAuth.signOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateTime orderDate = _parseDate(_dateController.text);
|
||||||
|
final String location = _globalLocationController.text;
|
||||||
|
|
||||||
|
int totalWorkers = 0;
|
||||||
|
double shiftCost = 0;
|
||||||
|
|
||||||
|
final List<_ShiftRoleKey> remainingOriginal =
|
||||||
|
List<_ShiftRoleKey>.from(_originalShiftRoles);
|
||||||
|
|
||||||
|
for (final Map<String, dynamic> pos in _positions) {
|
||||||
|
final String roleId = pos['roleId']?.toString() ?? '';
|
||||||
|
if (roleId.isEmpty) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String shiftId = pos['shiftId']?.toString() ?? _shiftId!;
|
||||||
|
final int count = pos['count'] as int;
|
||||||
|
final DateTime start = _parseTime(orderDate, pos['start_time'].toString());
|
||||||
|
final DateTime end = _parseTime(orderDate, pos['end_time'].toString());
|
||||||
|
final DateTime normalizedEnd =
|
||||||
|
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||||
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
|
final double rate = _rateForRole(roleId);
|
||||||
|
final double totalValue = rate * hours * count;
|
||||||
|
final String lunchBreak = pos['lunch_break'] as String;
|
||||||
|
|
||||||
|
totalWorkers += count;
|
||||||
|
shiftCost += totalValue;
|
||||||
|
|
||||||
|
final String? originalRoleId = pos['originalRoleId']?.toString();
|
||||||
|
remainingOriginal.removeWhere(
|
||||||
|
(_ShiftRoleKey key) =>
|
||||||
|
key.shiftId == shiftId && key.roleId == originalRoleId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (originalRoleId != null && originalRoleId.isNotEmpty) {
|
||||||
|
if (originalRoleId != roleId) {
|
||||||
|
await _dataConnect
|
||||||
|
.deleteShiftRole(shiftId: shiftId, roleId: originalRoleId)
|
||||||
|
.execute();
|
||||||
|
await _dataConnect
|
||||||
|
.createShiftRole(
|
||||||
|
shiftId: shiftId,
|
||||||
|
roleId: roleId,
|
||||||
|
count: count,
|
||||||
|
)
|
||||||
|
.startTime(_toTimestamp(start))
|
||||||
|
.endTime(_toTimestamp(normalizedEnd))
|
||||||
|
.hours(hours)
|
||||||
|
.breakType(_breakDurationFromValue(lunchBreak))
|
||||||
|
.totalValue(totalValue)
|
||||||
|
.execute();
|
||||||
|
} else {
|
||||||
|
await _dataConnect
|
||||||
|
.updateShiftRole(shiftId: shiftId, roleId: roleId)
|
||||||
|
.count(count)
|
||||||
|
.startTime(_toTimestamp(start))
|
||||||
|
.endTime(_toTimestamp(normalizedEnd))
|
||||||
|
.hours(hours)
|
||||||
|
.breakType(_breakDurationFromValue(lunchBreak))
|
||||||
|
.totalValue(totalValue)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await _dataConnect
|
||||||
|
.createShiftRole(
|
||||||
|
shiftId: shiftId,
|
||||||
|
roleId: roleId,
|
||||||
|
count: count,
|
||||||
|
)
|
||||||
|
.startTime(_toTimestamp(start))
|
||||||
|
.endTime(_toTimestamp(normalizedEnd))
|
||||||
|
.hours(hours)
|
||||||
|
.breakType(_breakDurationFromValue(lunchBreak))
|
||||||
|
.totalValue(totalValue)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final _ShiftRoleKey key in remainingOriginal) {
|
||||||
|
await _dataConnect
|
||||||
|
.deleteShiftRole(shiftId: key.shiftId, roleId: key.roleId)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _dataConnect
|
||||||
|
.updateOrder(id: widget.order.orderId)
|
||||||
|
.vendorId(_selectedVendor?.id)
|
||||||
|
.location(location)
|
||||||
|
.date(_toTimestamp(orderDate))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await _dataConnect
|
||||||
|
.updateShift(id: _shiftId!)
|
||||||
|
.title('shift 1 ${DateFormat('yyyy-MM-dd').format(orderDate)}')
|
||||||
|
.date(_toTimestamp(orderDate))
|
||||||
|
.location(location)
|
||||||
|
.locationAddress(location)
|
||||||
|
.workersNeeded(totalWorkers)
|
||||||
|
.cost(shiftCost)
|
||||||
|
.durationDays(1)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
void _addPosition() {
|
void _addPosition() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_positions.add(<String, dynamic>{
|
_positions.add(_emptyPosition());
|
||||||
'role': '',
|
|
||||||
'count': 1,
|
|
||||||
'start_time': '09:00',
|
|
||||||
'end_time': '17:00',
|
|
||||||
'lunch_break': 0,
|
|
||||||
'location': null,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,10 +1106,6 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
setState(() => _positions[index][key] = value);
|
setState(() => _positions[index][key] = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
double _calculateTotalCost() {
|
|
||||||
return widget.order.totalValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_isLoading && _showReview) {
|
if (_isLoading && _showReview) {
|
||||||
@@ -781,6 +1158,7 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
onChanged: (Vendor? vendor) {
|
onChanged: (Vendor? vendor) {
|
||||||
if (vendor != null) {
|
if (vendor != null) {
|
||||||
setState(() => _selectedVendor = vendor);
|
setState(() => _selectedVendor = vendor);
|
||||||
|
_loadRolesForVendor(vendor.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
items: _vendors.map((Vendor vendor) {
|
items: _vendors.map((Vendor vendor) {
|
||||||
@@ -956,30 +1334,32 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
|
|
||||||
_buildDropdownField(
|
_buildDropdownField(
|
||||||
hint: 'Select role',
|
hint: 'Select role',
|
||||||
value: pos['role'],
|
value: pos['roleId'],
|
||||||
items: <String>[
|
items: <String>[
|
||||||
...(_selectedVendor?.rates.keys.toList() ??
|
..._roles.map((_RoleOption role) => role.id),
|
||||||
<String>[
|
if (pos['roleId'] != null &&
|
||||||
'Server',
|
pos['roleId'].toString().isNotEmpty &&
|
||||||
'Bartender',
|
!_roles.any(
|
||||||
'Cook',
|
(_RoleOption role) => role.id == pos['roleId'].toString(),
|
||||||
'Busser',
|
))
|
||||||
'Host',
|
pos['roleId'].toString(),
|
||||||
'Barista',
|
|
||||||
'Dishwasher',
|
|
||||||
'Event Staff',
|
|
||||||
]),
|
|
||||||
if (pos['role'] != null &&
|
|
||||||
pos['role'].toString().isNotEmpty &&
|
|
||||||
!(_selectedVendor?.rates.keys.contains(pos['role']) ?? false))
|
|
||||||
pos['role'].toString(),
|
|
||||||
],
|
],
|
||||||
itemBuilder: (dynamic role) {
|
itemBuilder: (dynamic roleId) {
|
||||||
final double? rate = _selectedVendor?.rates[role];
|
final _RoleOption? role = _roleById(roleId.toString());
|
||||||
if (rate == null) return role.toString();
|
if (role == null) {
|
||||||
return '$role - \$${rate.toStringAsFixed(0)}/hr';
|
final String fallback = pos['roleName']?.toString() ?? '';
|
||||||
|
return fallback.isEmpty ? roleId.toString() : fallback;
|
||||||
|
}
|
||||||
|
return '${role.name} - \$${role.costPerHour.toStringAsFixed(0)}/hr';
|
||||||
|
},
|
||||||
|
onChanged: (dynamic val) {
|
||||||
|
final String roleId = val?.toString() ?? '';
|
||||||
|
final _RoleOption? role = _roleById(roleId);
|
||||||
|
setState(() {
|
||||||
|
_positions[index]['roleId'] = roleId;
|
||||||
|
_positions[index]['roleName'] = role?.name ?? '';
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onChanged: (dynamic val) => _updatePosition(index, 'role', val),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: UiConstants.space3),
|
const SizedBox(height: UiConstants.space3),
|
||||||
@@ -1117,10 +1497,16 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
_buildDropdownField(
|
_buildDropdownField(
|
||||||
hint: 'No break',
|
hint: 'No break',
|
||||||
value: pos['lunch_break'],
|
value: pos['lunch_break'],
|
||||||
items: <int>[0, 15, 30, 45, 60],
|
items: <String>['NO_BREAK', 'MIN_15', 'MIN_30'],
|
||||||
itemBuilder: (dynamic val) {
|
itemBuilder: (dynamic val) {
|
||||||
if (val == 0) return 'No break';
|
switch (val.toString()) {
|
||||||
return '$val min';
|
case 'MIN_15':
|
||||||
|
return '15 min';
|
||||||
|
case 'MIN_30':
|
||||||
|
return '30 min';
|
||||||
|
default:
|
||||||
|
return 'No break';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onChanged: (dynamic val) =>
|
onChanged: (dynamic val) =>
|
||||||
_updatePosition(index, 'lunch_break', val),
|
_updatePosition(index, 'lunch_break', val),
|
||||||
@@ -1379,7 +1765,7 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
text: 'Confirm & Save',
|
text: 'Confirm & Save',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
setState(() => _isLoading = true);
|
setState(() => _isLoading = true);
|
||||||
await Future<void>.delayed(const Duration(seconds: 1));
|
await _saveOrderChanges();
|
||||||
if (mounted) Navigator.pop(context);
|
if (mounted) Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1413,8 +1799,9 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildReviewPositionCard(Map<String, dynamic> pos) {
|
Widget _buildReviewPositionCard(Map<String, dynamic> pos) {
|
||||||
final double rate =
|
final String roleId = pos['roleId']?.toString() ?? '';
|
||||||
_selectedVendor?.rates[pos['role']] ?? widget.order.hourlyRate;
|
final _RoleOption? role = _roleById(roleId);
|
||||||
|
final double rate = role?.costPerHour ?? 0;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 12),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
@@ -1433,9 +1820,9 @@ class _OrderEditSheetState extends State<_OrderEditSheet> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
pos['role'].toString().isEmpty
|
(role?.name ?? pos['roleName']?.toString() ?? '').isEmpty
|
||||||
? 'Position'
|
? 'Position'
|
||||||
: pos['role'].toString(),
|
: (role?.name ?? pos['roleName']?.toString() ?? ''),
|
||||||
style: UiTypography.body2b.textPrimary,
|
style: UiTypography.body2b.textPrimary,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ mutation updateOrder(
|
|||||||
$businessId: UUID
|
$businessId: UUID
|
||||||
$location: String
|
$location: String
|
||||||
$status: OrderStatus
|
$status: OrderStatus
|
||||||
|
$date: Timestamp
|
||||||
$startDate: Timestamp
|
$startDate: Timestamp
|
||||||
$endDate: Timestamp
|
$endDate: Timestamp
|
||||||
$total: Float
|
$total: Float
|
||||||
@@ -76,6 +77,7 @@ mutation updateOrder(
|
|||||||
businessId: $businessId
|
businessId: $businessId
|
||||||
location: $location
|
location: $location
|
||||||
status: $status
|
status: $status
|
||||||
|
date: $date
|
||||||
startDate: $startDate
|
startDate: $startDate
|
||||||
endDate: $endDate
|
endDate: $endDate
|
||||||
total: $total
|
total: $total
|
||||||
|
|||||||
@@ -328,7 +328,110 @@ query listShiftRolesByBusinessAndDateRange(
|
|||||||
location
|
location
|
||||||
locationAddress
|
locationAddress
|
||||||
title
|
title
|
||||||
|
status
|
||||||
order { id }
|
order { id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#list shiftsroles for update order in client app
|
||||||
|
query listShiftRolesByBusinessAndOrder(
|
||||||
|
$businessId: UUID!
|
||||||
|
$orderId: UUID!
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
) @auth(level: USER) {
|
||||||
|
shiftRoles(
|
||||||
|
where: {
|
||||||
|
shift: {
|
||||||
|
orderId: { eq: $orderId }
|
||||||
|
order: { businessId: { eq: $businessId } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
orderBy: { createdAt: DESC }
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
shiftId
|
||||||
|
roleId
|
||||||
|
count
|
||||||
|
assigned
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
hours
|
||||||
|
breakType
|
||||||
|
totalValue
|
||||||
|
createdAt
|
||||||
|
|
||||||
|
role { id name costPerHour }
|
||||||
|
|
||||||
|
shift {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
date
|
||||||
|
orderId
|
||||||
|
location
|
||||||
|
locationAddress
|
||||||
|
|
||||||
|
order{
|
||||||
|
vendorId
|
||||||
|
date
|
||||||
|
location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#reorder get list by businessId
|
||||||
|
query listShiftRolesByBusinessDateRangeCompletedOrders(
|
||||||
|
$businessId: UUID!
|
||||||
|
$start: Timestamp!
|
||||||
|
$end: Timestamp!
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
) @auth(level: USER) {
|
||||||
|
shiftRoles(
|
||||||
|
where: {
|
||||||
|
shift: {
|
||||||
|
date: { ge: $start, le: $end }
|
||||||
|
order: {
|
||||||
|
businessId: { eq: $businessId }
|
||||||
|
status: { eq: COMPLETED }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
orderBy: { createdAt: DESC }
|
||||||
|
) {
|
||||||
|
shiftId
|
||||||
|
roleId
|
||||||
|
count
|
||||||
|
assigned
|
||||||
|
hours
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
totalValue
|
||||||
|
|
||||||
|
role {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
costPerHour
|
||||||
|
}
|
||||||
|
|
||||||
|
shift {
|
||||||
|
id
|
||||||
|
date
|
||||||
|
location
|
||||||
|
locationAddress
|
||||||
|
title
|
||||||
|
status
|
||||||
|
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
orderType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user