getting informatin of vendor and vendorroles
This commit is contained in:
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import firebase_app_check
|
|||||||
import firebase_auth
|
import firebase_auth
|
||||||
import firebase_core
|
import firebase_core
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
import url_launcher_macos
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin"))
|
FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin"))
|
||||||
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
|
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
|
||||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,13 @@
|
|||||||
|
|
||||||
#include <firebase_auth/firebase_auth_plugin_c_api.h>
|
#include <firebase_auth/firebase_auth_plugin_c_api.h>
|
||||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||||
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
FirebaseAuthPluginCApiRegisterWithRegistrar(
|
FirebaseAuthPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
|
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
|
||||||
FirebaseCorePluginCApiRegisterWithRegistrar(
|
FirebaseCorePluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
||||||
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
firebase_auth
|
firebase_auth
|
||||||
firebase_core
|
firebase_core
|
||||||
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
@@ -43,7 +43,12 @@ class ClientCreateOrderModule extends Module {
|
|||||||
// BLoCs
|
// BLoCs
|
||||||
i.addSingleton<ClientCreateOrderBloc>(ClientCreateOrderBloc.new);
|
i.addSingleton<ClientCreateOrderBloc>(ClientCreateOrderBloc.new);
|
||||||
i.add<RapidOrderBloc>(RapidOrderBloc.new);
|
i.add<RapidOrderBloc>(RapidOrderBloc.new);
|
||||||
i.add<OneTimeOrderBloc>(OneTimeOrderBloc.new);
|
i.add<OneTimeOrderBloc>(
|
||||||
|
() => OneTimeOrderBloc(
|
||||||
|
i.get<CreateOneTimeOrderUseCase>(),
|
||||||
|
ExampleConnector.instance,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
||||||
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
import 'package:krow_domain/krow_domain.dart' as domain;
|
||||||
import '../../domain/repositories/client_create_order_repository_interface.dart';
|
import '../../domain/repositories/client_create_order_repository_interface.dart';
|
||||||
@@ -56,176 +55,7 @@ class ClientCreateOrderRepositoryImpl
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> createRapidOrder(String description) async {
|
Future<void> createRapidOrder(String description) async {
|
||||||
final businessId = dc.ClientSessionStore.instance.session?.business?.id;
|
// TO-DO: connect IA and return array with the information.
|
||||||
if (businessId == null || businessId.isEmpty) {
|
throw UnimplementedError('Rapid order IA is not connected yet.');
|
||||||
await _firebaseAuth.signOut();
|
|
||||||
throw Exception('Business is missing. Please sign in again.');
|
|
||||||
}
|
|
||||||
|
|
||||||
final payload = _requestIa(description);
|
|
||||||
final orderTimestamp = _toTimestamp(payload.date);
|
|
||||||
|
|
||||||
final orderResult = await _dataConnect
|
|
||||||
.createOrder(businessId: businessId, orderType: dc.OrderType.RAPID)
|
|
||||||
.vendorId(payload.vendorId)
|
|
||||||
.hub(payload.hub)
|
|
||||||
.location(payload.location)
|
|
||||||
.status(dc.OrderStatus.POSTED)
|
|
||||||
.date(orderTimestamp)
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
final orderId = orderResult.data?.order_insert.id;
|
|
||||||
if (orderId == null) {
|
|
||||||
throw Exception('Order creation failed.');
|
|
||||||
}
|
|
||||||
|
|
||||||
final shiftIds = <String>[];
|
|
||||||
for (var i = 0; i < payload.shifts.length; i++) {
|
|
||||||
final shiftPayload = payload.shifts[i];
|
|
||||||
final shiftTitle = 'Shift ${i + 1} ${_formatDate(payload.date)}';
|
|
||||||
final shiftCost = shiftPayload.roles.fold<double>(
|
|
||||||
0,
|
|
||||||
(sum, role) => sum + role.totalValue,
|
|
||||||
);
|
|
||||||
|
|
||||||
final shiftResult = await _dataConnect
|
|
||||||
.createShift(title: shiftTitle, orderId: orderId)
|
|
||||||
.date(orderTimestamp)
|
|
||||||
.location(payload.location)
|
|
||||||
.locationAddress(payload.location)
|
|
||||||
.status(dc.ShiftStatus.PENDING)
|
|
||||||
.workersNeeded(shiftPayload.workersNeeded)
|
|
||||||
.filled(0)
|
|
||||||
.durationDays(1)
|
|
||||||
.cost(shiftCost)
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
final shiftId = shiftResult.data?.shift_insert.id;
|
|
||||||
if (shiftId == null) {
|
|
||||||
throw Exception('Shift creation failed.');
|
|
||||||
}
|
|
||||||
shiftIds.add(shiftId);
|
|
||||||
|
|
||||||
for (final role in shiftPayload.roles) {
|
|
||||||
await _dataConnect
|
|
||||||
.createShiftRole(
|
|
||||||
shiftId: shiftId,
|
|
||||||
roleId: role.roleId,
|
|
||||||
count: role.count,
|
|
||||||
)
|
|
||||||
.startTime(_toTimestamp(role.startTime))
|
|
||||||
.endTime(_toTimestamp(role.endTime))
|
|
||||||
.hours(role.hours)
|
|
||||||
.totalValue(role.totalValue)
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await _dataConnect
|
|
||||||
.updateOrder(id: orderId)
|
|
||||||
.shifts(fdc.AnyValue(shiftIds))
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
_RapidOrderPayload _requestIa(String description) {
|
|
||||||
final now = DateTime.now().toUtc();
|
|
||||||
final shiftStart = DateTime.utc(
|
|
||||||
now.year,
|
|
||||||
now.month,
|
|
||||||
now.day,
|
|
||||||
8,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
final shiftEnd = shiftStart.add(const Duration(hours: 6));
|
|
||||||
|
|
||||||
return _RapidOrderPayload(
|
|
||||||
vendorId: '00000000-0000-0000-0000-000000000001',
|
|
||||||
hub: 'Main Hub',
|
|
||||||
location: 'Main Location',
|
|
||||||
date: DateTime.utc(now.year, now.month, now.day),
|
|
||||||
shifts: [
|
|
||||||
_RapidShiftPayload(
|
|
||||||
workersNeeded: 3,
|
|
||||||
roles: [
|
|
||||||
_RapidShiftRolePayload(
|
|
||||||
roleId: '00000000-0000-0000-0000-000000000010',
|
|
||||||
count: 2,
|
|
||||||
startTime: shiftStart,
|
|
||||||
endTime: shiftEnd,
|
|
||||||
totalValue: 120,
|
|
||||||
),
|
|
||||||
_RapidShiftRolePayload(
|
|
||||||
roleId: '00000000-0000-0000-0000-000000000011',
|
|
||||||
count: 1,
|
|
||||||
startTime: shiftStart,
|
|
||||||
endTime: shiftEnd,
|
|
||||||
totalValue: 80,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fdc.Timestamp _toTimestamp(DateTime dateTime) {
|
|
||||||
final utc = dateTime.toUtc();
|
|
||||||
final seconds = utc.millisecondsSinceEpoch ~/ 1000;
|
|
||||||
final nanoseconds = (utc.microsecondsSinceEpoch % 1000000) * 1000;
|
|
||||||
return fdc.Timestamp(nanoseconds, seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _formatDate(DateTime dateTime) {
|
|
||||||
final utc = dateTime.toUtc();
|
|
||||||
final year = utc.year.toString().padLeft(4, '0');
|
|
||||||
final month = utc.month.toString().padLeft(2, '0');
|
|
||||||
final day = utc.day.toString().padLeft(2, '0');
|
|
||||||
return '$year-$month-$day';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RapidOrderPayload {
|
|
||||||
final String vendorId;
|
|
||||||
final String hub;
|
|
||||||
final String location;
|
|
||||||
final DateTime date;
|
|
||||||
final List<_RapidShiftPayload> shifts;
|
|
||||||
|
|
||||||
const _RapidOrderPayload({
|
|
||||||
required this.vendorId,
|
|
||||||
required this.hub,
|
|
||||||
required this.location,
|
|
||||||
required this.date,
|
|
||||||
required this.shifts,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RapidShiftPayload {
|
|
||||||
final int workersNeeded;
|
|
||||||
final List<_RapidShiftRolePayload> roles;
|
|
||||||
|
|
||||||
const _RapidShiftPayload({
|
|
||||||
required this.workersNeeded,
|
|
||||||
required this.roles,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RapidShiftRolePayload {
|
|
||||||
final String roleId;
|
|
||||||
final int count;
|
|
||||||
final DateTime startTime;
|
|
||||||
final DateTime endTime;
|
|
||||||
final double totalValue;
|
|
||||||
|
|
||||||
const _RapidShiftRolePayload({
|
|
||||||
required this.roleId,
|
|
||||||
required this.count,
|
|
||||||
required this.startTime,
|
|
||||||
required this.endTime,
|
|
||||||
required this.totalValue,
|
|
||||||
});
|
|
||||||
|
|
||||||
double get hours {
|
|
||||||
final minutes = endTime.difference(startTime).inMinutes;
|
|
||||||
return minutes / 60.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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';
|
||||||
import '../../domain/arguments/one_time_order_arguments.dart';
|
import '../../domain/arguments/one_time_order_arguments.dart';
|
||||||
import '../../domain/usecases/create_one_time_order_usecase.dart';
|
import '../../domain/usecases/create_one_time_order_usecase.dart';
|
||||||
@@ -7,7 +8,7 @@ import 'one_time_order_state.dart';
|
|||||||
|
|
||||||
/// BLoC for managing the multi-step one-time order creation form.
|
/// BLoC for managing the multi-step one-time order creation form.
|
||||||
class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||||
OneTimeOrderBloc(this._createOneTimeOrderUseCase)
|
OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._dataConnect)
|
||||||
: super(OneTimeOrderState.initial()) {
|
: super(OneTimeOrderState.initial()) {
|
||||||
on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded);
|
on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded);
|
||||||
on<OneTimeOrderVendorChanged>(_onVendorChanged);
|
on<OneTimeOrderVendorChanged>(_onVendorChanged);
|
||||||
@@ -18,52 +19,64 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
|||||||
on<OneTimeOrderPositionUpdated>(_onPositionUpdated);
|
on<OneTimeOrderPositionUpdated>(_onPositionUpdated);
|
||||||
on<OneTimeOrderSubmitted>(_onSubmitted);
|
on<OneTimeOrderSubmitted>(_onSubmitted);
|
||||||
|
|
||||||
// Initial load of mock vendors
|
_loadVendors();
|
||||||
add(
|
|
||||||
const OneTimeOrderVendorsLoaded(<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,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase;
|
final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase;
|
||||||
|
final dc.ExampleConnector _dataConnect;
|
||||||
|
|
||||||
|
Future<void> _loadVendors() async {
|
||||||
|
try {
|
||||||
|
final result = await _dataConnect.listVendors().execute();
|
||||||
|
final vendors = result.data.vendors
|
||||||
|
.map(
|
||||||
|
(vendor) => Vendor(
|
||||||
|
id: vendor.id,
|
||||||
|
name: vendor.companyName,
|
||||||
|
rates: const <String, double>{},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
add(OneTimeOrderVendorsLoaded(vendors));
|
||||||
|
} catch (_) {
|
||||||
|
add(const OneTimeOrderVendorsLoaded(<Vendor>[]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadRolesForVendor(String vendorId) async {
|
||||||
|
try {
|
||||||
|
final result = await _dataConnect.listRolesByVendorId(
|
||||||
|
vendorId: vendorId,
|
||||||
|
).execute();
|
||||||
|
final roles = result.data.roles
|
||||||
|
.map(
|
||||||
|
(role) => OneTimeOrderRoleOption(
|
||||||
|
id: role.id,
|
||||||
|
name: role.name,
|
||||||
|
costPerHour: role.costPerHour,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
emit(state.copyWith(roles: roles));
|
||||||
|
} catch (_) {
|
||||||
|
emit(state.copyWith(roles: const <OneTimeOrderRoleOption>[]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onVendorsLoaded(
|
void _onVendorsLoaded(
|
||||||
OneTimeOrderVendorsLoaded event,
|
OneTimeOrderVendorsLoaded event,
|
||||||
Emitter<OneTimeOrderState> emit,
|
Emitter<OneTimeOrderState> emit,
|
||||||
) {
|
) {
|
||||||
|
final Vendor? selectedVendor =
|
||||||
|
event.vendors.isNotEmpty ? event.vendors.first : null;
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
vendors: event.vendors,
|
vendors: event.vendors,
|
||||||
selectedVendor: event.vendors.isNotEmpty ? event.vendors.first : null,
|
selectedVendor: selectedVendor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
if (selectedVendor != null) {
|
||||||
|
_loadRolesForVendor(selectedVendor.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onVendorChanged(
|
void _onVendorChanged(
|
||||||
@@ -71,6 +84,7 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
|||||||
Emitter<OneTimeOrderState> emit,
|
Emitter<OneTimeOrderState> emit,
|
||||||
) {
|
) {
|
||||||
emit(state.copyWith(selectedVendor: event.vendor));
|
emit(state.copyWith(selectedVendor: event.vendor));
|
||||||
|
_loadRolesForVendor(event.vendor.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onDateChanged(
|
void _onDateChanged(
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class OneTimeOrderState extends Equatable {
|
|||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
this.vendors = const <Vendor>[],
|
this.vendors = const <Vendor>[],
|
||||||
this.selectedVendor,
|
this.selectedVendor,
|
||||||
|
this.roles = const <OneTimeOrderRoleOption>[],
|
||||||
});
|
});
|
||||||
|
|
||||||
factory OneTimeOrderState.initial() {
|
factory OneTimeOrderState.initial() {
|
||||||
@@ -22,6 +23,7 @@ class OneTimeOrderState extends Equatable {
|
|||||||
OneTimeOrderPosition(role: '', count: 1, startTime: '', endTime: ''),
|
OneTimeOrderPosition(role: '', count: 1, startTime: '', endTime: ''),
|
||||||
],
|
],
|
||||||
vendors: const <Vendor>[],
|
vendors: const <Vendor>[],
|
||||||
|
roles: const <OneTimeOrderRoleOption>[],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
@@ -31,6 +33,7 @@ class OneTimeOrderState extends Equatable {
|
|||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
final List<Vendor> vendors;
|
final List<Vendor> vendors;
|
||||||
final Vendor? selectedVendor;
|
final Vendor? selectedVendor;
|
||||||
|
final List<OneTimeOrderRoleOption> roles;
|
||||||
|
|
||||||
OneTimeOrderState copyWith({
|
OneTimeOrderState copyWith({
|
||||||
DateTime? date,
|
DateTime? date,
|
||||||
@@ -40,6 +43,7 @@ class OneTimeOrderState extends Equatable {
|
|||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
List<Vendor>? vendors,
|
List<Vendor>? vendors,
|
||||||
Vendor? selectedVendor,
|
Vendor? selectedVendor,
|
||||||
|
List<OneTimeOrderRoleOption>? roles,
|
||||||
}) {
|
}) {
|
||||||
return OneTimeOrderState(
|
return OneTimeOrderState(
|
||||||
date: date ?? this.date,
|
date: date ?? this.date,
|
||||||
@@ -49,6 +53,7 @@ class OneTimeOrderState extends Equatable {
|
|||||||
errorMessage: errorMessage ?? this.errorMessage,
|
errorMessage: errorMessage ?? this.errorMessage,
|
||||||
vendors: vendors ?? this.vendors,
|
vendors: vendors ?? this.vendors,
|
||||||
selectedVendor: selectedVendor ?? this.selectedVendor,
|
selectedVendor: selectedVendor ?? this.selectedVendor,
|
||||||
|
roles: roles ?? this.roles,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,5 +66,21 @@ class OneTimeOrderState extends Equatable {
|
|||||||
errorMessage,
|
errorMessage,
|
||||||
vendors,
|
vendors,
|
||||||
selectedVendor,
|
selectedVendor,
|
||||||
|
roles,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class OneTimeOrderRoleOption extends Equatable {
|
||||||
|
const OneTimeOrderRoleOption({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => <Object?>[id, name, costPerHour];
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,14 +64,17 @@ class RapidOrderBloc extends Bloc<RapidOrderEvent, RapidOrderState> {
|
|||||||
final RapidOrderState currentState = state;
|
final RapidOrderState currentState = state;
|
||||||
if (currentState is RapidOrderInitial) {
|
if (currentState is RapidOrderInitial) {
|
||||||
final String message = currentState.message;
|
final String message = currentState.message;
|
||||||
|
print('RapidOrder submit: message="$message"');
|
||||||
emit(const RapidOrderSubmitting());
|
emit(const RapidOrderSubmitting());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _createRapidOrderUseCase(
|
await _createRapidOrderUseCase(
|
||||||
RapidOrderArguments(description: message),
|
RapidOrderArguments(description: message),
|
||||||
);
|
);
|
||||||
|
print('RapidOrder submit: success');
|
||||||
emit(const RapidOrderSuccess());
|
emit(const RapidOrderSuccess());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print('RapidOrder submit: error=$e');
|
||||||
emit(RapidOrderFailure(e.toString()));
|
emit(RapidOrderFailure(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ 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';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
import '../../blocs/one_time_order_state.dart';
|
||||||
|
|
||||||
/// A card widget for editing a specific position in a one-time order.
|
/// A card widget for editing a specific position in a one-time order.
|
||||||
/// Matches the prototype layout while using design system tokens.
|
/// Matches the prototype layout while using design system tokens.
|
||||||
@@ -19,7 +20,7 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
|||||||
required this.startLabel,
|
required this.startLabel,
|
||||||
required this.endLabel,
|
required this.endLabel,
|
||||||
required this.lunchLabel,
|
required this.lunchLabel,
|
||||||
this.vendor,
|
required this.roles,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -56,8 +57,8 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
|||||||
/// Label for the lunch break.
|
/// Label for the lunch break.
|
||||||
final String lunchLabel;
|
final String lunchLabel;
|
||||||
|
|
||||||
/// The current selected vendor to determine rates.
|
/// Available roles for the selected vendor.
|
||||||
final Vendor? vendor;
|
final List<OneTimeOrderRoleOption> roles;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -118,26 +119,7 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
|||||||
onUpdated(position.copyWith(role: val));
|
onUpdated(position.copyWith(role: val));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
items:
|
items: _buildRoleItems(),
|
||||||
<String>{
|
|
||||||
...(vendor?.rates.keys ?? <String>[]),
|
|
||||||
if (position.role.isNotEmpty &&
|
|
||||||
!(vendor?.rates.keys.contains(position.role) ??
|
|
||||||
false))
|
|
||||||
position.role,
|
|
||||||
}.map((String role) {
|
|
||||||
final double? rate = vendor?.rates[role];
|
|
||||||
final String label = rate == null
|
|
||||||
? role
|
|
||||||
: '$role - \$${rate.toStringAsFixed(0)}/hr';
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: role,
|
|
||||||
child: Text(
|
|
||||||
label,
|
|
||||||
style: UiTypography.body2r.textPrimary,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -317,4 +299,33 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<DropdownMenuItem<String>> _buildRoleItems() {
|
||||||
|
final items = roles
|
||||||
|
.map(
|
||||||
|
(role) => DropdownMenuItem<String>(
|
||||||
|
value: role.id,
|
||||||
|
child: Text(
|
||||||
|
'${role.name} - \$${role.costPerHour.toStringAsFixed(0)}',
|
||||||
|
style: UiTypography.body2r.textPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final hasSelected = roles.any((role) => role.id == position.role);
|
||||||
|
if (position.role.isNotEmpty && !hasSelected) {
|
||||||
|
items.add(
|
||||||
|
DropdownMenuItem<String>(
|
||||||
|
value: position.role,
|
||||||
|
child: Text(
|
||||||
|
position.role,
|
||||||
|
style: UiTypography.body2r.textPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ class _OneTimeOrderForm extends StatelessWidget {
|
|||||||
startLabel: labels.start_label,
|
startLabel: labels.start_label,
|
||||||
endLabel: labels.end_label,
|
endLabel: labels.end_label,
|
||||||
lunchLabel: labels.lunch_break_label,
|
lunchLabel: labels.lunch_break_label,
|
||||||
vendor: state.selectedVendor,
|
roles: state.roles,
|
||||||
onUpdated: (OneTimeOrderPosition updated) {
|
onUpdated: (OneTimeOrderPosition updated) {
|
||||||
BlocProvider.of<OneTimeOrderBloc>(
|
BlocProvider.of<OneTimeOrderBloc>(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -288,9 +288,12 @@ class _RapidOrderActions extends StatelessWidget {
|
|||||||
trailingIcon: UiIcons.arrowRight,
|
trailingIcon: UiIcons.arrowRight,
|
||||||
onPressed: isSubmitting || isMessageEmpty
|
onPressed: isSubmitting || isMessageEmpty
|
||||||
? null
|
? null
|
||||||
: () => BlocProvider.of<RapidOrderBloc>(
|
: () {
|
||||||
context,
|
print('RapidOrder send pressed');
|
||||||
).add(const RapidOrderSubmitted()),
|
BlocProvider.of<RapidOrderBloc>(
|
||||||
|
context,
|
||||||
|
).add(const RapidOrderSubmitted());
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user