reoder view working
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
# Basic Usage
|
||||
|
||||
```dart
|
||||
ExampleConnector.instance.createVendorBenefitPlan(createVendorBenefitPlanVariables).execute();
|
||||
ExampleConnector.instance.updateVendorBenefitPlan(updateVendorBenefitPlanVariables).execute();
|
||||
ExampleConnector.instance.deleteVendorBenefitPlan(deleteVendorBenefitPlanVariables).execute();
|
||||
ExampleConnector.instance.createWorkforce(createWorkforceVariables).execute();
|
||||
ExampleConnector.instance.updateWorkforce(updateWorkforceVariables).execute();
|
||||
ExampleConnector.instance.deactivateWorkforce(deactivateWorkforceVariables).execute();
|
||||
ExampleConnector.instance.createApplication(createApplicationVariables).execute();
|
||||
ExampleConnector.instance.updateApplicationStatus(updateApplicationStatusVariables).execute();
|
||||
ExampleConnector.instance.deleteApplication(deleteApplicationVariables).execute();
|
||||
ExampleConnector.instance.listCertificates().execute();
|
||||
ExampleConnector.instance.createTeamMember(createTeamMemberVariables).execute();
|
||||
ExampleConnector.instance.updateTeamMember(updateTeamMemberVariables).execute();
|
||||
ExampleConnector.instance.updateTeamMemberInviteStatus(updateTeamMemberInviteStatusVariables).execute();
|
||||
ExampleConnector.instance.acceptInviteByCode(acceptInviteByCodeVariables).execute();
|
||||
ExampleConnector.instance.cancelInviteByCode(cancelInviteByCodeVariables).execute();
|
||||
ExampleConnector.instance.deleteTeamMember(deleteTeamMemberVariables).execute();
|
||||
ExampleConnector.instance.listActivityLogs(listActivityLogsVariables).execute();
|
||||
ExampleConnector.instance.getActivityLogById(getActivityLogByIdVariables).execute();
|
||||
ExampleConnector.instance.listActivityLogsByUserId(listActivityLogsByUserIdVariables).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:
|
||||
|
||||
```dart
|
||||
await ExampleConnector.instance.updateStaffDocument({ ... })
|
||||
.status(...)
|
||||
await ExampleConnector.instance.getRapidOrders({ ... })
|
||||
.offset(...)
|
||||
.execute();
|
||||
```
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,3 +66,4 @@ export 'src/entities/support/working_area.dart';
|
||||
|
||||
// Home
|
||||
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,
|
||||
];
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'src/data/repositories_impl/home_repository_impl.dart';
|
||||
import 'src/domain/repositories/home_repository_interface.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/presentation/blocs/client_home_bloc.dart';
|
||||
import 'src/presentation/pages/client_home_page.dart';
|
||||
@@ -24,17 +25,22 @@ class ClientHomeModule extends Module {
|
||||
void binds(Injector i) {
|
||||
// Repositories
|
||||
i.addLazySingleton<HomeRepositoryInterface>(
|
||||
() => HomeRepositoryImpl(i.get<HomeRepositoryMock>()),
|
||||
() => HomeRepositoryImpl(
|
||||
i.get<HomeRepositoryMock>(),
|
||||
ExampleConnector.instance,
|
||||
),
|
||||
);
|
||||
|
||||
// UseCases
|
||||
i.addLazySingleton(GetDashboardDataUseCase.new);
|
||||
i.addLazySingleton(GetRecentReordersUseCase.new);
|
||||
i.addLazySingleton(GetUserSessionDataUseCase.new);
|
||||
|
||||
// BLoCs
|
||||
i.add<ClientHomeBloc>(
|
||||
() => ClientHomeBloc(
|
||||
getDashboardDataUseCase: i.get<GetDashboardDataUseCase>(),
|
||||
getRecentReordersUseCase: i.get<GetRecentReordersUseCase>(),
|
||||
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_domain/krow_domain.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).
|
||||
class HomeRepositoryImpl implements HomeRepositoryInterface {
|
||||
final HomeRepositoryMock _mock;
|
||||
final ExampleConnector _dataConnect;
|
||||
|
||||
/// Creates a [HomeRepositoryImpl].
|
||||
///
|
||||
/// Requires a [HomeRepositoryMock] to perform data operations.
|
||||
HomeRepositoryImpl(this._mock);
|
||||
HomeRepositoryImpl(this._mock, this._dataConnect);
|
||||
|
||||
@override
|
||||
Future<HomeDashboardData> getDashboardData() {
|
||||
@@ -27,4 +29,62 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
|
||||
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).
|
||||
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:krow_domain/krow_domain.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 'client_home_event.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.
|
||||
class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
|
||||
final GetDashboardDataUseCase _getDashboardDataUseCase;
|
||||
final GetRecentReordersUseCase _getRecentReordersUseCase;
|
||||
final GetUserSessionDataUseCase _getUserSessionDataUseCase;
|
||||
|
||||
ClientHomeBloc({
|
||||
required GetDashboardDataUseCase getDashboardDataUseCase,
|
||||
required GetRecentReordersUseCase getRecentReordersUseCase,
|
||||
required GetUserSessionDataUseCase getUserSessionDataUseCase,
|
||||
}) : _getDashboardDataUseCase = getDashboardDataUseCase,
|
||||
_getRecentReordersUseCase = getRecentReordersUseCase,
|
||||
_getUserSessionDataUseCase = getUserSessionDataUseCase,
|
||||
super(const ClientHomeState()) {
|
||||
on<ClientHomeStarted>(_onStarted);
|
||||
@@ -35,11 +39,13 @@ class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
|
||||
|
||||
// Get dashboard data
|
||||
final HomeDashboardData data = await _getDashboardDataUseCase();
|
||||
final List<ReorderItem> reorderItems = await _getRecentReordersUseCase();
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: ClientHomeStatus.success,
|
||||
dashboardData: data,
|
||||
reorderItems: reorderItems,
|
||||
businessName: sessionData.businessName,
|
||||
photoUrl: sessionData.photoUrl,
|
||||
),
|
||||
|
||||
@@ -12,6 +12,7 @@ class ClientHomeState extends Equatable {
|
||||
final bool isEditMode;
|
||||
final String? errorMessage;
|
||||
final HomeDashboardData dashboardData;
|
||||
final List<ReorderItem> reorderItems;
|
||||
final String businessName;
|
||||
final String? photoUrl;
|
||||
|
||||
@@ -19,9 +20,11 @@ class ClientHomeState extends Equatable {
|
||||
this.status = ClientHomeStatus.initial,
|
||||
this.widgetOrder = const <String>[
|
||||
'actions',
|
||||
'reorder',
|
||||
],
|
||||
this.widgetVisibility = const <String, bool>{
|
||||
'actions': true,
|
||||
'reorder': true,
|
||||
},
|
||||
this.isEditMode = false,
|
||||
this.errorMessage,
|
||||
@@ -33,6 +36,7 @@ class ClientHomeState extends Equatable {
|
||||
totalNeeded: 10,
|
||||
totalFilled: 8,
|
||||
),
|
||||
this.reorderItems = const <ReorderItem>[],
|
||||
this.businessName = 'Your Company',
|
||||
this.photoUrl,
|
||||
});
|
||||
@@ -44,6 +48,7 @@ class ClientHomeState extends Equatable {
|
||||
bool? isEditMode,
|
||||
String? errorMessage,
|
||||
HomeDashboardData? dashboardData,
|
||||
List<ReorderItem>? reorderItems,
|
||||
String? businessName,
|
||||
String? photoUrl,
|
||||
}) {
|
||||
@@ -54,6 +59,7 @@ class ClientHomeState extends Equatable {
|
||||
isEditMode: isEditMode ?? this.isEditMode,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
dashboardData: dashboardData ?? this.dashboardData,
|
||||
reorderItems: reorderItems ?? this.reorderItems,
|
||||
businessName: businessName ?? this.businessName,
|
||||
photoUrl: photoUrl ?? this.photoUrl,
|
||||
);
|
||||
@@ -67,6 +73,7 @@ class ClientHomeState extends Equatable {
|
||||
isEditMode,
|
||||
errorMessage,
|
||||
dashboardData,
|
||||
reorderItems,
|
||||
businessName,
|
||||
photoUrl,
|
||||
];
|
||||
|
||||
@@ -64,6 +64,7 @@ class DashboardWidgetBuilder extends StatelessWidget {
|
||||
);
|
||||
case 'reorder':
|
||||
return ReorderWidget(
|
||||
orders: state.reorderItems,
|
||||
onReorderPressed: (Map<String, dynamic> data) {
|
||||
ClientHomeSheets.showOrderFormSheet(
|
||||
context,
|
||||
|
||||
@@ -1,46 +1,28 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
/// A widget that allows clients to reorder recent shifts.
|
||||
class ReorderWidget extends StatelessWidget {
|
||||
/// Recent completed orders for reorder.
|
||||
final List<ReorderItem> orders;
|
||||
|
||||
/// Callback when a reorder button is pressed.
|
||||
final Function(Map<String, dynamic> shiftData) onReorderPressed;
|
||||
|
||||
/// Creates a [ReorderWidget].
|
||||
const ReorderWidget({super.key, required this.onReorderPressed});
|
||||
const ReorderWidget({
|
||||
super.key,
|
||||
required this.orders,
|
||||
required this.onReorderPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TranslationsClientHomeReorderEn i18n = t.client_home.reorder;
|
||||
|
||||
// Mock recent 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',
|
||||
},
|
||||
];
|
||||
final List<ReorderItem> recentOrders = orders;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -60,11 +42,9 @@ class ReorderWidget extends StatelessWidget {
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final Map<String, Object> order = recentOrders[index];
|
||||
final ReorderItem order = recentOrders[index];
|
||||
final double totalCost =
|
||||
(order['hourlyRate'] as double) *
|
||||
(order['hours'] as int) *
|
||||
(order['workers'] as int);
|
||||
order.hourlyRate * order.hours * order.workers;
|
||||
|
||||
return Container(
|
||||
width: 260,
|
||||
@@ -110,12 +90,12 @@ class ReorderWidget extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
order['title'] as String,
|
||||
order.title,
|
||||
style: UiTypography.body2b,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
Text(
|
||||
order['location'] as String,
|
||||
order.location,
|
||||
style:
|
||||
UiTypography.footnote1r.textSecondary,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -135,9 +115,9 @@ class ReorderWidget extends StatelessWidget {
|
||||
),
|
||||
Text(
|
||||
i18n.per_hr(
|
||||
amount: order['hourlyRate'].toString(),
|
||||
amount: order.hourlyRate.toString(),
|
||||
) +
|
||||
' · ${order['hours']}h',
|
||||
' · ${order.hours}h',
|
||||
style: UiTypography.footnote2r.textSecondary,
|
||||
),
|
||||
],
|
||||
@@ -149,7 +129,7 @@ class ReorderWidget extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
_Badge(
|
||||
icon: UiIcons.success,
|
||||
text: order['type'] as String,
|
||||
text: order.type,
|
||||
color: const Color(0xFF2563EB),
|
||||
bg: const Color(0xFF2563EB),
|
||||
textColor: UiColors.white,
|
||||
@@ -157,7 +137,7 @@ class ReorderWidget extends StatelessWidget {
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
_Badge(
|
||||
icon: UiIcons.building,
|
||||
text: '${order['workers']}',
|
||||
text: '${order.workers}',
|
||||
color: const Color(0xFF334155),
|
||||
bg: const Color(0xFFF1F5F9),
|
||||
textColor: const Color(0xFF334155),
|
||||
@@ -169,7 +149,15 @@ class ReorderWidget extends StatelessWidget {
|
||||
height: 28,
|
||||
width: double.infinity,
|
||||
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(
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.white,
|
||||
|
||||
Reference in New Issue
Block a user