Merge branch '208-p0-auth-05-get-started-screen' of https://github.com/Oloodi/krow-workforce into 208-p0-auth-05-get-started-screen
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
||||
import 'data/repositories_impl/client_create_order_repository_impl.dart';
|
||||
import 'domain/repositories/client_create_order_repository_interface.dart';
|
||||
import 'domain/usecases/create_one_time_order_usecase.dart';
|
||||
@@ -29,7 +30,8 @@ class ClientCreateOrderModule extends Module {
|
||||
// Repositories
|
||||
i.addLazySingleton<ClientCreateOrderRepositoryInterface>(
|
||||
() => ClientCreateOrderRepositoryImpl(
|
||||
orderMock: i.get<OrderRepositoryMock>(),
|
||||
firebaseAuth: firebase.FirebaseAuth.instance,
|
||||
dataConnect: ExampleConnector.instance,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -41,7 +43,12 @@ class ClientCreateOrderModule extends Module {
|
||||
// BLoCs
|
||||
i.addSingleton<ClientCreateOrderBloc>(ClientCreateOrderBloc.new);
|
||||
i.add<RapidOrderBloc>(RapidOrderBloc.new);
|
||||
i.add<OneTimeOrderBloc>(OneTimeOrderBloc.new);
|
||||
i.add<OneTimeOrderBloc>(
|
||||
() => OneTimeOrderBloc(
|
||||
i.get<CreateOneTimeOrderUseCase>(),
|
||||
ExampleConnector.instance,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:krow_data_connect/krow_data_connect.dart' hide OrderType;
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
||||
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
||||
import '../../domain/repositories/client_create_order_repository_interface.dart';
|
||||
|
||||
/// Implementation of [ClientCreateOrderRepositoryInterface].
|
||||
@@ -12,29 +15,171 @@ import '../../domain/repositories/client_create_order_repository_interface.dart'
|
||||
/// on delegation and data mapping, without business logic.
|
||||
class ClientCreateOrderRepositoryImpl
|
||||
implements ClientCreateOrderRepositoryInterface {
|
||||
/// Creates a [ClientCreateOrderRepositoryImpl].
|
||||
///
|
||||
/// Requires the [OrderRepositoryMock] from the shared Data Connect package.
|
||||
/// TODO: Inject and use ExampleConnector when real mutations are available.
|
||||
ClientCreateOrderRepositoryImpl({required OrderRepositoryMock orderMock})
|
||||
: _orderMock = orderMock;
|
||||
final OrderRepositoryMock _orderMock;
|
||||
ClientCreateOrderRepositoryImpl({
|
||||
required firebase.FirebaseAuth firebaseAuth,
|
||||
required dc.ExampleConnector dataConnect,
|
||||
}) : _firebaseAuth = firebaseAuth,
|
||||
_dataConnect = dataConnect;
|
||||
|
||||
final firebase.FirebaseAuth _firebaseAuth;
|
||||
final dc.ExampleConnector _dataConnect;
|
||||
|
||||
@override
|
||||
Future<List<OrderType>> getOrderTypes() {
|
||||
// Delegates to Data Connect layer
|
||||
return _orderMock.getOrderTypes();
|
||||
Future<List<domain.OrderType>> getOrderTypes() {
|
||||
return Future.value(const <domain.OrderType>[
|
||||
domain.OrderType(
|
||||
id: 'rapid',
|
||||
titleKey: 'client_create_order.types.rapid',
|
||||
descriptionKey: 'client_create_order.types.rapid_desc',
|
||||
),
|
||||
domain.OrderType(
|
||||
id: 'one-time',
|
||||
titleKey: 'client_create_order.types.one_time',
|
||||
descriptionKey: 'client_create_order.types.one_time_desc',
|
||||
),
|
||||
domain.OrderType(
|
||||
id: 'recurring',
|
||||
titleKey: 'client_create_order.types.recurring',
|
||||
descriptionKey: 'client_create_order.types.recurring_desc',
|
||||
),
|
||||
domain.OrderType(
|
||||
id: 'permanent',
|
||||
titleKey: 'client_create_order.types.permanent',
|
||||
descriptionKey: 'client_create_order.types.permanent_desc',
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> createOneTimeOrder(OneTimeOrder order) {
|
||||
// Delegates to Data Connect layer
|
||||
return _orderMock.createOneTimeOrder(order);
|
||||
Future<void> createOneTimeOrder(domain.OneTimeOrder order) async {
|
||||
final businessId = dc.ClientSessionStore.instance.session?.business?.id;
|
||||
if (businessId == null || businessId.isEmpty) {
|
||||
await _firebaseAuth.signOut();
|
||||
throw Exception('Business is missing. Please sign in again.');
|
||||
}
|
||||
final vendorId = order.vendorId;
|
||||
if (vendorId == null || vendorId.isEmpty) {
|
||||
throw Exception('Vendor is missing.');
|
||||
}
|
||||
|
||||
final orderTimestamp = _toTimestamp(order.date);
|
||||
final orderResult = await _dataConnect
|
||||
.createOrder(businessId: businessId, orderType: dc.OrderType.ONE_TIME)
|
||||
.vendorId(vendorId)
|
||||
.location(order.location)
|
||||
.status(dc.OrderStatus.POSTED)
|
||||
.date(orderTimestamp)
|
||||
.execute();
|
||||
|
||||
final orderId = orderResult.data?.order_insert.id;
|
||||
if (orderId == null) {
|
||||
throw Exception('Order creation failed.');
|
||||
}
|
||||
|
||||
final workersNeeded = order.positions.fold<int>(
|
||||
0,
|
||||
(sum, position) => sum + position.count,
|
||||
);
|
||||
final shiftTitle = 'Shift 1 ${_formatDate(order.date)}';
|
||||
final shiftCost = _calculateShiftCost(order);
|
||||
|
||||
final shiftResult = await _dataConnect
|
||||
.createShift(title: shiftTitle, orderId: orderId)
|
||||
.date(orderTimestamp)
|
||||
.location(order.location)
|
||||
.locationAddress(order.location)
|
||||
.status(dc.ShiftStatus.PENDING)
|
||||
.workersNeeded(workersNeeded)
|
||||
.filled(0)
|
||||
.durationDays(1)
|
||||
.cost(shiftCost)
|
||||
.execute();
|
||||
|
||||
final shiftId = shiftResult.data?.shift_insert.id;
|
||||
if (shiftId == null) {
|
||||
throw Exception('Shift creation failed.');
|
||||
}
|
||||
|
||||
for (final position in order.positions) {
|
||||
final start = _parseTime(order.date, position.startTime);
|
||||
final end = _parseTime(order.date, position.endTime);
|
||||
final normalizedEnd =
|
||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||
final hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||
final rate = order.roleRates[position.role] ?? 0;
|
||||
final totalValue = rate * hours;
|
||||
|
||||
await _dataConnect
|
||||
.createShiftRole(
|
||||
shiftId: shiftId,
|
||||
roleId: position.role,
|
||||
count: position.count,
|
||||
)
|
||||
.startTime(_toTimestamp(start))
|
||||
.endTime(_toTimestamp(normalizedEnd))
|
||||
.hours(hours)
|
||||
.totalValue(totalValue)
|
||||
.execute();
|
||||
}
|
||||
|
||||
await _dataConnect
|
||||
.updateOrder(id: orderId)
|
||||
.shifts(fdc.AnyValue(<String>[shiftId]))
|
||||
.execute();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> createRapidOrder(String description) {
|
||||
// Delegates to Data Connect layer
|
||||
return _orderMock.createRapidOrder(description);
|
||||
Future<void> createRapidOrder(String description) async {
|
||||
// TO-DO: connect IA and return array with the information.
|
||||
throw UnimplementedError('Rapid order IA is not connected yet.');
|
||||
}
|
||||
|
||||
double _calculateShiftCost(domain.OneTimeOrder order) {
|
||||
double total = 0;
|
||||
for (final position in order.positions) {
|
||||
final start = _parseTime(order.date, position.startTime);
|
||||
final end = _parseTime(order.date, position.endTime);
|
||||
final normalizedEnd =
|
||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||
final hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||
final rate = order.roleRates[position.role] ?? 0;
|
||||
total += rate * hours;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
DateTime _parseTime(DateTime date, String time) {
|
||||
if (time.trim().isEmpty) {
|
||||
throw Exception('Shift time is missing.');
|
||||
}
|
||||
|
||||
DateTime parsed;
|
||||
try {
|
||||
parsed = DateFormat.jm().parse(time);
|
||||
} catch (_) {
|
||||
parsed = DateFormat.Hm().parse(time);
|
||||
}
|
||||
|
||||
return DateTime(
|
||||
date.year,
|
||||
date.month,
|
||||
date.day,
|
||||
parsed.hour,
|
||||
parsed.minute,
|
||||
);
|
||||
}
|
||||
|
||||
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 year = dateTime.year.toString().padLeft(4, '0');
|
||||
final month = dateTime.month.toString().padLeft(2, '0');
|
||||
final day = dateTime.day.toString().padLeft(2, '0');
|
||||
return '$year-$month-$day';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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 '../../domain/arguments/one_time_order_arguments.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.
|
||||
class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
OneTimeOrderBloc(this._createOneTimeOrderUseCase)
|
||||
OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._dataConnect)
|
||||
: super(OneTimeOrderState.initial()) {
|
||||
on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded);
|
||||
on<OneTimeOrderVendorChanged>(_onVendorChanged);
|
||||
@@ -18,52 +19,64 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
on<OneTimeOrderPositionUpdated>(_onPositionUpdated);
|
||||
on<OneTimeOrderSubmitted>(_onSubmitted);
|
||||
|
||||
// Initial load of mock vendors
|
||||
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,
|
||||
},
|
||||
),
|
||||
]),
|
||||
);
|
||||
_loadVendors();
|
||||
}
|
||||
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(
|
||||
OneTimeOrderVendorsLoaded event,
|
||||
Emitter<OneTimeOrderState> emit,
|
||||
) {
|
||||
final Vendor? selectedVendor =
|
||||
event.vendors.isNotEmpty ? event.vendors.first : null;
|
||||
emit(
|
||||
state.copyWith(
|
||||
vendors: event.vendors,
|
||||
selectedVendor: event.vendors.isNotEmpty ? event.vendors.first : null,
|
||||
selectedVendor: selectedVendor,
|
||||
),
|
||||
);
|
||||
if (selectedVendor != null) {
|
||||
_loadRolesForVendor(selectedVendor.id);
|
||||
}
|
||||
}
|
||||
|
||||
void _onVendorChanged(
|
||||
@@ -71,6 +84,7 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
Emitter<OneTimeOrderState> emit,
|
||||
) {
|
||||
emit(state.copyWith(selectedVendor: event.vendor));
|
||||
_loadRolesForVendor(event.vendor.id);
|
||||
}
|
||||
|
||||
void _onDateChanged(
|
||||
@@ -131,11 +145,15 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
) async {
|
||||
emit(state.copyWith(status: OneTimeOrderStatus.loading));
|
||||
try {
|
||||
final Map<String, double> roleRates = <String, double>{
|
||||
for (final role in state.roles) role.id: role.costPerHour,
|
||||
};
|
||||
final OneTimeOrder order = OneTimeOrder(
|
||||
date: state.date,
|
||||
location: state.location,
|
||||
positions: state.positions,
|
||||
// In a real app, we'd pass the vendorId here
|
||||
vendorId: state.selectedVendor?.id,
|
||||
roleRates: roleRates,
|
||||
);
|
||||
await _createOneTimeOrderUseCase(OneTimeOrderArguments(order: order));
|
||||
emit(state.copyWith(status: OneTimeOrderStatus.success));
|
||||
|
||||
@@ -12,6 +12,7 @@ class OneTimeOrderState extends Equatable {
|
||||
this.errorMessage,
|
||||
this.vendors = const <Vendor>[],
|
||||
this.selectedVendor,
|
||||
this.roles = const <OneTimeOrderRoleOption>[],
|
||||
});
|
||||
|
||||
factory OneTimeOrderState.initial() {
|
||||
@@ -22,6 +23,7 @@ class OneTimeOrderState extends Equatable {
|
||||
OneTimeOrderPosition(role: '', count: 1, startTime: '', endTime: ''),
|
||||
],
|
||||
vendors: const <Vendor>[],
|
||||
roles: const <OneTimeOrderRoleOption>[],
|
||||
);
|
||||
}
|
||||
final DateTime date;
|
||||
@@ -31,6 +33,7 @@ class OneTimeOrderState extends Equatable {
|
||||
final String? errorMessage;
|
||||
final List<Vendor> vendors;
|
||||
final Vendor? selectedVendor;
|
||||
final List<OneTimeOrderRoleOption> roles;
|
||||
|
||||
OneTimeOrderState copyWith({
|
||||
DateTime? date,
|
||||
@@ -40,6 +43,7 @@ class OneTimeOrderState extends Equatable {
|
||||
String? errorMessage,
|
||||
List<Vendor>? vendors,
|
||||
Vendor? selectedVendor,
|
||||
List<OneTimeOrderRoleOption>? roles,
|
||||
}) {
|
||||
return OneTimeOrderState(
|
||||
date: date ?? this.date,
|
||||
@@ -49,6 +53,7 @@ class OneTimeOrderState extends Equatable {
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
vendors: vendors ?? this.vendors,
|
||||
selectedVendor: selectedVendor ?? this.selectedVendor,
|
||||
roles: roles ?? this.roles,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,5 +66,21 @@ class OneTimeOrderState extends Equatable {
|
||||
errorMessage,
|
||||
vendors,
|
||||
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;
|
||||
if (currentState is RapidOrderInitial) {
|
||||
final String message = currentState.message;
|
||||
print('RapidOrder submit: message="$message"');
|
||||
emit(const RapidOrderSubmitting());
|
||||
|
||||
try {
|
||||
await _createRapidOrderUseCase(
|
||||
RapidOrderArguments(description: message),
|
||||
);
|
||||
print('RapidOrder submit: success');
|
||||
emit(const RapidOrderSuccess());
|
||||
} catch (e) {
|
||||
print('RapidOrder submit: error=$e');
|
||||
emit(RapidOrderFailure(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ 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';
|
||||
import '../../blocs/one_time_order_state.dart';
|
||||
|
||||
/// A card widget for editing a specific position in a one-time order.
|
||||
/// Matches the prototype layout while using design system tokens.
|
||||
@@ -19,7 +20,7 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
required this.startLabel,
|
||||
required this.endLabel,
|
||||
required this.lunchLabel,
|
||||
this.vendor,
|
||||
required this.roles,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -56,8 +57,8 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
/// Label for the lunch break.
|
||||
final String lunchLabel;
|
||||
|
||||
/// The current selected vendor to determine rates.
|
||||
final Vendor? vendor;
|
||||
/// Available roles for the selected vendor.
|
||||
final List<OneTimeOrderRoleOption> roles;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -118,26 +119,7 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
onUpdated(position.copyWith(role: val));
|
||||
}
|
||||
},
|
||||
items:
|
||||
<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(),
|
||||
items: _buildRoleItems(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -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,
|
||||
endLabel: labels.end_label,
|
||||
lunchLabel: labels.lunch_break_label,
|
||||
vendor: state.selectedVendor,
|
||||
roles: state.roles,
|
||||
onUpdated: (OneTimeOrderPosition updated) {
|
||||
BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
|
||||
@@ -288,9 +288,12 @@ class _RapidOrderActions extends StatelessWidget {
|
||||
trailingIcon: UiIcons.arrowRight,
|
||||
onPressed: isSubmitting || isMessageEmpty
|
||||
? null
|
||||
: () => BlocProvider.of<RapidOrderBloc>(
|
||||
context,
|
||||
).add(const RapidOrderSubmitted()),
|
||||
: () {
|
||||
print('RapidOrder send pressed');
|
||||
BlocProvider.of<RapidOrderBloc>(
|
||||
context,
|
||||
).add(const RapidOrderSubmitted());
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user