From 19eda09620946fce0fc9feb5a2d1d79b20e5a2c3 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Mon, 16 Feb 2026 17:35:15 -0500 Subject: [PATCH] feat: Refactor ClientCreateOrderRepositoryImpl and OneTimeOrderBloc to utilize DataConnectService, removing FirebaseAuth dependency --- .../lib/src/create_order_module.dart | 15 +- .../client_create_order_repository_impl.dart | 200 ++++++++---------- .../blocs/one_time_order_bloc.dart | 16 +- 3 files changed, 99 insertions(+), 132 deletions(-) diff --git a/apps/mobile/packages/features/client/create_order/lib/src/create_order_module.dart b/apps/mobile/packages/features/client/create_order/lib/src/create_order_module.dart index db759e08..0e2624e2 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/create_order_module.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/create_order_module.dart @@ -2,7 +2,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:krow_core/core.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,12 +28,7 @@ class ClientCreateOrderModule extends Module { @override void binds(Injector i) { // Repositories - i.addLazySingleton( - () => ClientCreateOrderRepositoryImpl( - firebaseAuth: firebase.FirebaseAuth.instance, - dataConnect: ExampleConnector.instance, - ), - ); + i.addLazySingleton(ClientCreateOrderRepositoryImpl.new); // UseCases i.addLazySingleton(GetOrderTypesUseCase.new); @@ -44,12 +38,7 @@ class ClientCreateOrderModule extends Module { // BLoCs i.add(ClientCreateOrderBloc.new); i.add(RapidOrderBloc.new); - i.add( - () => OneTimeOrderBloc( - i.get(), - ExampleConnector.instance, - ), - ); + i.add(OneTimeOrderBloc.new); } @override diff --git a/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart b/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart index eb905a2a..0ae65a1a 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart @@ -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:intl/intl.dart'; 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 /// on delegation and data mapping, without business logic. -class ClientCreateOrderRepositoryImpl - with dc.DataErrorHandler - implements ClientCreateOrderRepositoryInterface { +class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInterface { ClientCreateOrderRepositoryImpl({ - required firebase.FirebaseAuth firebaseAuth, - required dc.ExampleConnector dataConnect, - }) : _firebaseAuth = firebaseAuth, - _dataConnect = dataConnect; + required dc.DataConnectService service, + }) : _service = service; - final firebase.FirebaseAuth _firebaseAuth; - final dc.ExampleConnector _dataConnect; + final dc.DataConnectService _service; @override Future> getOrderTypes() { - return Future.value(const [ + return Future>.value(const [ domain.OrderType( id: 'one-time', titleKey: 'client_create_order.types.one_time', @@ -55,100 +49,95 @@ class ClientCreateOrderRepositoryImpl @override Future createOneTimeOrder(domain.OneTimeOrder order) async { - final String? 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 String? vendorId = order.vendorId; - if (vendorId == null || vendorId.isEmpty) { - throw Exception('Vendor is missing.'); - } - final domain.OneTimeOrderHubDetails? hub = order.hub; - if (hub == null || hub.id.isEmpty) { - throw Exception('Hub is missing.'); - } + return _service.run(() async { + final String businessId = await _service.getBusinessId(); + final String? vendorId = order.vendorId; + if (vendorId == null || vendorId.isEmpty) { + throw Exception('Vendor is missing.'); + } + final domain.OneTimeOrderHubDetails? hub = order.hub; + if (hub == null || hub.id.isEmpty) { + throw Exception('Hub is missing.'); + } - final DateTime orderDateOnly = DateTime( - order.date.year, - order.date.month, - order.date.day, - ); - final fdc.Timestamp orderTimestamp = _toTimestamp(orderDateOnly); - final fdc.OperationResult - orderResult = await executeProtected(() => _dataConnect - .createOrder( - businessId: businessId, - orderType: dc.OrderType.ONE_TIME, - teamHubId: hub.id, + final DateTime orderDateOnly = DateTime( + order.date.year, + order.date.month, + order.date.day, + ); + final fdc.Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly); + final fdc.OperationResult orderResult = + await _service.connector + .createOrder( + businessId: businessId, + orderType: dc.OrderType.ONE_TIME, + 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( + 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 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) - .eventName(order.eventName) - .status(dc.OrderStatus.POSTED) - .date(orderTimestamp) - .execute()); + .startTime(_service.toTimestamp(start)) + .endTime(_service.toTimestamp(normalizedEnd)) + .hours(hours) + .breakType(_breakDurationFromValue(position.lunchBreak)) + .isBreakPaid(_isBreakPaid(position.lunchBreak)) + .totalValue(totalValue) + .execute(); + } - final String orderId = orderResult.data.order_insert.id; - - final int workersNeeded = order.positions.fold( - 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 - 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([shiftId])) - .execute()); + await _service.connector + .updateOrder(id: orderId, teamHubId: hub.id) + .shifts(fdc.AnyValue([shiftId])) + .execute(); + }); } @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) { final String year = dateTime.year.toString().padLeft(4, '0'); final String month = dateTime.month.toString().padLeft(2, '0'); diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/blocs/one_time_order_bloc.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/blocs/one_time_order_bloc.dart index 30fe20e1..7e11f0eb 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/blocs/one_time_order_bloc.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/blocs/one_time_order_bloc.dart @@ -11,7 +11,7 @@ import 'one_time_order_state.dart'; /// BLoC for managing the multi-step one-time order creation form. class OneTimeOrderBloc extends Bloc with BlocErrorHandler, SafeBloc { - OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._dataConnect) + OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._service) : super(OneTimeOrderState.initial()) { on(_onVendorsLoaded); on(_onVendorChanged); @@ -28,13 +28,13 @@ class OneTimeOrderBloc extends Bloc _loadHubs(); } final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase; - final dc.ExampleConnector _dataConnect; + final dc.DataConnectService _service; Future _loadVendors() async { final List? vendors = await handleErrorWithResult( action: () async { final QueryResult result = - await _dataConnect.listVendors().execute(); + await _service.connector.listVendors().execute(); return result.data.vendors .map( (dc.ListVendorsVendors vendor) => Vendor( @@ -57,7 +57,7 @@ class OneTimeOrderBloc extends Bloc final List? roles = await handleErrorWithResult( action: () async { final QueryResult - result = await _dataConnect.listRolesByVendorId(vendorId: vendorId).execute(); + result = await _service.connector.listRolesByVendorId(vendorId: vendorId).execute(); return result.data.roles .map( (dc.ListRolesByVendorIdRoles role) => OneTimeOrderRoleOption( @@ -79,13 +79,9 @@ class OneTimeOrderBloc extends Bloc Future _loadHubs() async { final List? hubs = await handleErrorWithResult( action: () async { - final String? businessId = - dc.ClientSessionStore.instance.session?.business?.id; - if (businessId == null || businessId.isEmpty) { - return []; - } + final String businessId = await _service.getBusinessId(); final QueryResult - result = await _dataConnect + result = await _service.connector .listTeamHubsByOwnerId(ownerId: businessId) .execute(); return result.data.teamHubs