feat: Refactor ClientCreateOrderRepositoryImpl and OneTimeOrderBloc to utilize DataConnectService, removing FirebaseAuth dependency

This commit is contained in:
Achintha Isuru
2026-02-16 17:35:15 -05:00
parent fc0bb5828c
commit 19eda09620
3 changed files with 99 additions and 132 deletions

View File

@@ -2,7 +2,6 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/core.dart'; import 'package:krow_core/core.dart';
import 'package:krow_data_connect/krow_data_connect.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 'data/repositories_impl/client_create_order_repository_impl.dart';
import 'domain/repositories/client_create_order_repository_interface.dart'; import 'domain/repositories/client_create_order_repository_interface.dart';
import 'domain/usecases/create_one_time_order_usecase.dart'; import 'domain/usecases/create_one_time_order_usecase.dart';
@@ -29,12 +28,7 @@ class ClientCreateOrderModule extends Module {
@override @override
void binds(Injector i) { void binds(Injector i) {
// Repositories // Repositories
i.addLazySingleton<ClientCreateOrderRepositoryInterface>( i.addLazySingleton<ClientCreateOrderRepositoryInterface>(ClientCreateOrderRepositoryImpl.new);
() => ClientCreateOrderRepositoryImpl(
firebaseAuth: firebase.FirebaseAuth.instance,
dataConnect: ExampleConnector.instance,
),
);
// UseCases // UseCases
i.addLazySingleton(GetOrderTypesUseCase.new); i.addLazySingleton(GetOrderTypesUseCase.new);
@@ -44,12 +38,7 @@ class ClientCreateOrderModule extends Module {
// BLoCs // BLoCs
i.add<ClientCreateOrderBloc>(ClientCreateOrderBloc.new); i.add<ClientCreateOrderBloc>(ClientCreateOrderBloc.new);
i.add<RapidOrderBloc>(RapidOrderBloc.new); i.add<RapidOrderBloc>(RapidOrderBloc.new);
i.add<OneTimeOrderBloc>( i.add<OneTimeOrderBloc>(OneTimeOrderBloc.new);
() => OneTimeOrderBloc(
i.get<CreateOneTimeOrderUseCase>(),
ExampleConnector.instance,
),
);
} }
@override @override

View File

@@ -1,4 +1,3 @@
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc; import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:krow_data_connect/krow_data_connect.dart' as dc; import 'package:krow_data_connect/krow_data_connect.dart' as dc;
@@ -13,21 +12,16 @@ import '../../domain/repositories/client_create_order_repository_interface.dart'
/// ///
/// It follows the KROW Clean Architecture by keeping the data layer focused /// It follows the KROW Clean Architecture by keeping the data layer focused
/// on delegation and data mapping, without business logic. /// on delegation and data mapping, without business logic.
class ClientCreateOrderRepositoryImpl class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInterface {
with dc.DataErrorHandler
implements ClientCreateOrderRepositoryInterface {
ClientCreateOrderRepositoryImpl({ ClientCreateOrderRepositoryImpl({
required firebase.FirebaseAuth firebaseAuth, required dc.DataConnectService service,
required dc.ExampleConnector dataConnect, }) : _service = service;
}) : _firebaseAuth = firebaseAuth,
_dataConnect = dataConnect;
final firebase.FirebaseAuth _firebaseAuth; final dc.DataConnectService _service;
final dc.ExampleConnector _dataConnect;
@override @override
Future<List<domain.OrderType>> getOrderTypes() { Future<List<domain.OrderType>> getOrderTypes() {
return Future.value(const <domain.OrderType>[ return Future<List<domain.OrderType>>.value(const <domain.OrderType>[
domain.OrderType( domain.OrderType(
id: 'one-time', id: 'one-time',
titleKey: 'client_create_order.types.one_time', titleKey: 'client_create_order.types.one_time',
@@ -55,100 +49,95 @@ class ClientCreateOrderRepositoryImpl
@override @override
Future<void> createOneTimeOrder(domain.OneTimeOrder order) async { Future<void> createOneTimeOrder(domain.OneTimeOrder order) async {
final String? businessId = dc.ClientSessionStore.instance.session?.business?.id; return _service.run(() async {
if (businessId == null || businessId.isEmpty) { final String businessId = await _service.getBusinessId();
await _firebaseAuth.signOut(); final String? vendorId = order.vendorId;
throw Exception('Business is missing. Please sign in again.'); if (vendorId == null || vendorId.isEmpty) {
} throw Exception('Vendor is missing.');
final String? vendorId = order.vendorId; }
if (vendorId == null || vendorId.isEmpty) { final domain.OneTimeOrderHubDetails? hub = order.hub;
throw Exception('Vendor is missing.'); if (hub == null || hub.id.isEmpty) {
} throw Exception('Hub is missing.');
final domain.OneTimeOrderHubDetails? hub = order.hub; }
if (hub == null || hub.id.isEmpty) {
throw Exception('Hub is missing.');
}
final DateTime orderDateOnly = DateTime( final DateTime orderDateOnly = DateTime(
order.date.year, order.date.year,
order.date.month, order.date.month,
order.date.day, order.date.day,
); );
final fdc.Timestamp orderTimestamp = _toTimestamp(orderDateOnly); final fdc.Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
final fdc.OperationResult<dc.CreateOrderData, dc.CreateOrderVariables> final fdc.OperationResult<dc.CreateOrderData, dc.CreateOrderVariables> orderResult =
orderResult = await executeProtected(() => _dataConnect await _service.connector
.createOrder( .createOrder(
businessId: businessId, businessId: businessId,
orderType: dc.OrderType.ONE_TIME, orderType: dc.OrderType.ONE_TIME,
teamHubId: hub.id, teamHubId: hub.id,
)
.vendorId(vendorId)
.eventName(order.eventName)
.status(dc.OrderStatus.POSTED)
.date(orderTimestamp)
.execute();
final String orderId = orderResult.data.order_insert.id;
final int workersNeeded = order.positions.fold<int>(
0,
(int sum, domain.OneTimeOrderPosition position) => sum + position.count,
);
final String shiftTitle = 'Shift 1 ${_formatDate(order.date)}';
final double shiftCost = _calculateShiftCost(order);
final fdc.OperationResult<dc.CreateShiftData, dc.CreateShiftVariables> shiftResult =
await _service.connector
.createShift(title: shiftTitle, orderId: orderId)
.date(orderTimestamp)
.location(hub.name)
.locationAddress(hub.address)
.latitude(hub.latitude)
.longitude(hub.longitude)
.placeId(hub.placeId)
.city(hub.city)
.state(hub.state)
.street(hub.street)
.country(hub.country)
.status(dc.ShiftStatus.PENDING)
.workersNeeded(workersNeeded)
.filled(0)
.durationDays(1)
.cost(shiftCost)
.execute();
final String shiftId = shiftResult.data.shift_insert.id;
for (final domain.OneTimeOrderPosition position in order.positions) {
final DateTime start = _parseTime(order.date, position.startTime);
final DateTime end = _parseTime(order.date, position.endTime);
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 = order.roleRates[position.role] ?? 0;
final double totalValue = rate * hours * position.count;
await _service.connector
.createShiftRole(
shiftId: shiftId,
roleId: position.role,
count: position.count,
) )
.vendorId(vendorId) .startTime(_service.toTimestamp(start))
.eventName(order.eventName) .endTime(_service.toTimestamp(normalizedEnd))
.status(dc.OrderStatus.POSTED) .hours(hours)
.date(orderTimestamp) .breakType(_breakDurationFromValue(position.lunchBreak))
.execute()); .isBreakPaid(_isBreakPaid(position.lunchBreak))
.totalValue(totalValue)
.execute();
}
final String orderId = orderResult.data.order_insert.id; await _service.connector
.updateOrder(id: orderId, teamHubId: hub.id)
final int workersNeeded = order.positions.fold<int>( .shifts(fdc.AnyValue(<String>[shiftId]))
0, .execute();
(int sum, domain.OneTimeOrderPosition position) => sum + position.count, });
);
final String shiftTitle = 'Shift 1 ${_formatDate(order.date)}';
final double shiftCost = _calculateShiftCost(order);
final fdc.OperationResult<dc.CreateShiftData, dc.CreateShiftVariables>
shiftResult = await executeProtected(() => _dataConnect
.createShift(title: shiftTitle, orderId: orderId)
.date(orderTimestamp)
.location(hub.name)
.locationAddress(hub.address)
.latitude(hub.latitude)
.longitude(hub.longitude)
.placeId(hub.placeId)
.city(hub.city)
.state(hub.state)
.street(hub.street)
.country(hub.country)
.status(dc.ShiftStatus.PENDING)
.workersNeeded(workersNeeded)
.filled(0)
.durationDays(1)
.cost(shiftCost)
.execute());
final String shiftId = shiftResult.data.shift_insert.id;
for (final domain.OneTimeOrderPosition position in order.positions) {
final DateTime start = _parseTime(order.date, position.startTime);
final DateTime end = _parseTime(order.date, position.endTime);
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 = order.roleRates[position.role] ?? 0;
final double totalValue = rate * hours * position.count;
await executeProtected(() => _dataConnect
.createShiftRole(
shiftId: shiftId,
roleId: position.role,
count: position.count,
)
.startTime(_toTimestamp(start))
.endTime(_toTimestamp(normalizedEnd))
.hours(hours)
.breakType(_breakDurationFromValue(position.lunchBreak))
.isBreakPaid(_isBreakPaid(position.lunchBreak))
.totalValue(totalValue)
.execute());
}
await executeProtected(() => _dataConnect
.updateOrder(id: orderId, teamHubId: hub.id)
.shifts(fdc.AnyValue(<String>[shiftId]))
.execute());
} }
@override @override
@@ -213,13 +202,6 @@ class ClientCreateOrderRepositoryImpl
); );
} }
fdc.Timestamp _toTimestamp(DateTime dateTime) {
final DateTime utc = dateTime.toUtc();
final int seconds = utc.millisecondsSinceEpoch ~/ 1000;
final int nanoseconds = (utc.microsecondsSinceEpoch % 1000000) * 1000;
return fdc.Timestamp(nanoseconds, seconds);
}
String _formatDate(DateTime dateTime) { String _formatDate(DateTime dateTime) {
final String year = dateTime.year.toString().padLeft(4, '0'); final String year = dateTime.year.toString().padLeft(4, '0');
final String month = dateTime.month.toString().padLeft(2, '0'); final String month = dateTime.month.toString().padLeft(2, '0');

View File

@@ -11,7 +11,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>
with BlocErrorHandler<OneTimeOrderState>, SafeBloc<OneTimeOrderEvent, OneTimeOrderState> { with BlocErrorHandler<OneTimeOrderState>, SafeBloc<OneTimeOrderEvent, OneTimeOrderState> {
OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._dataConnect) OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._service)
: super(OneTimeOrderState.initial()) { : super(OneTimeOrderState.initial()) {
on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded); on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded);
on<OneTimeOrderVendorChanged>(_onVendorChanged); on<OneTimeOrderVendorChanged>(_onVendorChanged);
@@ -28,13 +28,13 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
_loadHubs(); _loadHubs();
} }
final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase; final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase;
final dc.ExampleConnector _dataConnect; final dc.DataConnectService _service;
Future<void> _loadVendors() async { Future<void> _loadVendors() async {
final List<Vendor>? vendors = await handleErrorWithResult( final List<Vendor>? vendors = await handleErrorWithResult(
action: () async { action: () async {
final QueryResult<dc.ListVendorsData, void> result = final QueryResult<dc.ListVendorsData, void> result =
await _dataConnect.listVendors().execute(); await _service.connector.listVendors().execute();
return result.data.vendors return result.data.vendors
.map( .map(
(dc.ListVendorsVendors vendor) => Vendor( (dc.ListVendorsVendors vendor) => Vendor(
@@ -57,7 +57,7 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
final List<OneTimeOrderRoleOption>? roles = await handleErrorWithResult( final List<OneTimeOrderRoleOption>? roles = await handleErrorWithResult(
action: () async { action: () async {
final QueryResult<dc.ListRolesByVendorIdData, dc.ListRolesByVendorIdVariables> final QueryResult<dc.ListRolesByVendorIdData, dc.ListRolesByVendorIdVariables>
result = await _dataConnect.listRolesByVendorId(vendorId: vendorId).execute(); result = await _service.connector.listRolesByVendorId(vendorId: vendorId).execute();
return result.data.roles return result.data.roles
.map( .map(
(dc.ListRolesByVendorIdRoles role) => OneTimeOrderRoleOption( (dc.ListRolesByVendorIdRoles role) => OneTimeOrderRoleOption(
@@ -79,13 +79,9 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
Future<void> _loadHubs() async { Future<void> _loadHubs() async {
final List<OneTimeOrderHubOption>? hubs = await handleErrorWithResult( final List<OneTimeOrderHubOption>? hubs = await handleErrorWithResult(
action: () async { action: () async {
final String? businessId = final String businessId = await _service.getBusinessId();
dc.ClientSessionStore.instance.session?.business?.id;
if (businessId == null || businessId.isEmpty) {
return <OneTimeOrderHubOption>[];
}
final QueryResult<dc.ListTeamHubsByOwnerIdData, dc.ListTeamHubsByOwnerIdVariables> final QueryResult<dc.ListTeamHubsByOwnerIdData, dc.ListTeamHubsByOwnerIdVariables>
result = await _dataConnect result = await _service.connector
.listTeamHubsByOwnerId(ownerId: businessId) .listTeamHubsByOwnerId(ownerId: businessId)
.execute(); .execute();
return result.data.teamHubs return result.data.teamHubs