refactor: centralize data connect error handling and resolve build issues across applications

This commit addresses several critical issues across the mobile monorepo:

1. Centralized Error Handling: Integrated DataErrorHandler mixin into all repository implementations, ensuring consistent mapping of Data Connect exceptions to domain AppExceptions.
2. Build Stabilization: Fixed numerous type mismatches, parameter signature errors in widgets (e.g., google_places_flutter itemBuilder), and naming conflicts (StaffSession, FirebaseAuth).
3. Code Quality: Applied 'dart fix' across all modified packages and manually cleared debug print statements and UI clutter.
4. Mono-repo alignment: Standardized Data Connect usage and aliasing ('dc.') for better maintainability.

Signed-off-by: Suriya <suriya@tenext.in>
This commit is contained in:
2026-02-06 13:28:57 +05:30
parent e0636e46a3
commit 5e7bf0d5c0
150 changed files with 1506 additions and 2547 deletions

View File

@@ -1,4 +1,4 @@
library client_hubs;
library;
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/core.dart';

View File

@@ -14,10 +14,11 @@ import 'package:krow_domain/krow_domain.dart'
NotAuthenticatedException;
import '../../domain/repositories/hub_repository_interface.dart';
import '../../util/hubs_constants.dart';
/// Implementation of [HubRepositoryInterface] backed by Data Connect.
class HubRepositoryImpl implements HubRepositoryInterface {
class HubRepositoryImpl
with dc.DataErrorHandler
implements HubRepositoryInterface {
HubRepositoryImpl({
required firebase.FirebaseAuth firebaseAuth,
required dc.ExampleConnector dataConnect,
@@ -57,27 +58,23 @@ class HubRepositoryImpl implements HubRepositoryInterface {
final String? countryValue = country ?? placeAddress?.country;
final String? zipCodeValue = zipCode ?? placeAddress?.zipCode;
final OperationResult<dc.CreateTeamHubData, dc.CreateTeamHubVariables> result = await _dataConnect
.createTeamHub(
teamId: teamId,
hubName: name,
address: address,
)
.placeId(placeId)
.latitude(latitude)
.longitude(longitude)
.city(cityValue?.isNotEmpty == true ? cityValue : '')
.state(stateValue)
.street(streetValue)
.country(countryValue)
.zipCode(zipCodeValue)
.execute();
final String? createdId = result.data?.teamHub_insert.id;
if (createdId == null) {
throw HubCreationFailedException(
technicalMessage: 'teamHub_insert returned null for hub: $name',
);
}
final OperationResult<dc.CreateTeamHubData, dc.CreateTeamHubVariables>
result = await executeProtected(() => _dataConnect
.createTeamHub(
teamId: teamId,
hubName: name,
address: address,
)
.placeId(placeId)
.latitude(latitude)
.longitude(longitude)
.city(cityValue?.isNotEmpty == true ? cityValue : '')
.state(stateValue)
.street(streetValue)
.country(countryValue)
.zipCode(zipCodeValue)
.execute());
final String createdId = result.data.teamHub_insert.id;
final List<domain.Hub> hubs = await _fetchHubsForTeam(
teamId: teamId,
@@ -111,14 +108,14 @@ class HubRepositoryImpl implements HubRepositoryInterface {
);
}
final QueryResult<
dc.ListOrdersByBusinessAndTeamHubData,
dc.ListOrdersByBusinessAndTeamHubVariables> result = await _dataConnect
.listOrdersByBusinessAndTeamHub(
businessId: businessId,
teamHubId: id,
)
.execute();
final QueryResult<dc.ListOrdersByBusinessAndTeamHubData,
dc.ListOrdersByBusinessAndTeamHubVariables> result =
await executeProtected(() => _dataConnect
.listOrdersByBusinessAndTeamHub(
businessId: businessId,
teamHubId: id,
)
.execute());
if (result.data.orders.isNotEmpty) {
throw HubHasOrdersException(
@@ -126,7 +123,7 @@ class HubRepositoryImpl implements HubRepositoryInterface {
);
}
await _dataConnect.deleteTeamHub(id: id).execute();
await executeProtected(() => _dataConnect.deleteTeamHub(id: id).execute());
}
@override
@@ -169,9 +166,11 @@ class HubRepositoryImpl implements HubRepositoryInterface {
);
}
final QueryResult<dc.GetBusinessesByUserIdData, dc.GetBusinessesByUserIdVariables> result = await _dataConnect.getBusinessesByUserId(
userId: user.uid,
).execute();
final QueryResult<dc.GetBusinessesByUserIdData,
dc.GetBusinessesByUserIdVariables> result =
await executeProtected(() => _dataConnect.getBusinessesByUserId(
userId: user.uid,
).execute());
if (result.data.businesses.isEmpty) {
await _firebaseAuth.signOut();
throw BusinessNotFoundException(
@@ -203,9 +202,10 @@ class HubRepositoryImpl implements HubRepositoryInterface {
Future<String> _getOrCreateTeamId(
dc.GetBusinessesByUserIdBusinesses business,
) async {
final QueryResult<dc.GetTeamsByOwnerIdData, dc.GetTeamsByOwnerIdVariables> teamsResult = await _dataConnect.getTeamsByOwnerId(
ownerId: business.id,
).execute();
final QueryResult<dc.GetTeamsByOwnerIdData, dc.GetTeamsByOwnerIdVariables>
teamsResult = await executeProtected(() => _dataConnect.getTeamsByOwnerId(
ownerId: business.id,
).execute());
if (teamsResult.data.teams.isNotEmpty) {
return teamsResult.data.teams.first.id;
}
@@ -220,13 +220,10 @@ class HubRepositoryImpl implements HubRepositoryInterface {
createTeamBuilder.email(business.email);
}
final OperationResult<dc.CreateTeamData, dc.CreateTeamVariables> createTeamResult = await createTeamBuilder.execute();
final String? teamId = createTeamResult.data?.team_insert.id;
if (teamId == null) {
throw HubCreationFailedException(
technicalMessage: 'Team creation failed for business ${business.id}',
);
}
final OperationResult<dc.CreateTeamData, dc.CreateTeamVariables>
createTeamResult =
await executeProtected(() => createTeamBuilder.execute());
final String teamId = createTeamResult.data.team_insert.id;
return teamId;
}
@@ -235,9 +232,11 @@ class HubRepositoryImpl implements HubRepositoryInterface {
required String teamId,
required String businessId,
}) async {
final QueryResult<dc.GetTeamHubsByTeamIdData, dc.GetTeamHubsByTeamIdVariables> hubsResult = await _dataConnect.getTeamHubsByTeamId(
teamId: teamId,
).execute();
final QueryResult<dc.GetTeamHubsByTeamIdData,
dc.GetTeamHubsByTeamIdVariables> hubsResult =
await executeProtected(() => _dataConnect.getTeamHubsByTeamId(
teamId: teamId,
).execute());
return hubsResult.data.teamHubs
.map(
@@ -318,13 +317,13 @@ class HubRepositoryImpl implements HubRepositoryInterface {
}
}
final String? streetValue = <String?>[streetNumber, route]
.where((String? value) => value != null && value!.isNotEmpty)
final String streetValue = <String?>[streetNumber, route]
.where((String? value) => value != null && value.isNotEmpty)
.join(' ')
.trim();
return _PlaceAddress(
street: streetValue?.isEmpty == true ? null : streetValue,
street: streetValue.isEmpty == true ? null : streetValue,
city: city,
state: state,
country: country,

View File

@@ -4,17 +4,17 @@ import 'package:krow_core/core.dart';
///
/// Encapsulates the hub ID and the NFC tag ID to be assigned.
class AssignNfcTagArguments extends UseCaseArgument {
/// Creates an [AssignNfcTagArguments] instance.
///
/// Both [hubId] and [nfcTagId] are required.
const AssignNfcTagArguments({required this.hubId, required this.nfcTagId});
/// The unique identifier of the hub.
final String hubId;
/// The unique identifier of the NFC tag.
final String nfcTagId;
/// Creates an [AssignNfcTagArguments] instance.
///
/// Both [hubId] and [nfcTagId] are required.
const AssignNfcTagArguments({required this.hubId, required this.nfcTagId});
@override
List<Object?> get props => <Object?>[hubId, nfcTagId];
}

View File

@@ -4,20 +4,6 @@ import 'package:krow_core/core.dart';
///
/// Encapsulates the name and address of the hub to be created.
class CreateHubArguments extends UseCaseArgument {
/// The name of the hub.
final String name;
/// The physical address of the hub.
final String address;
final String? placeId;
final double? latitude;
final double? longitude;
final String? city;
final String? state;
final String? street;
final String? country;
final String? zipCode;
/// Creates a [CreateHubArguments] instance.
///
@@ -34,6 +20,20 @@ class CreateHubArguments extends UseCaseArgument {
this.country,
this.zipCode,
});
/// The name of the hub.
final String name;
/// The physical address of the hub.
final String address;
final String? placeId;
final double? latitude;
final double? longitude;
final String? city;
final String? state;
final String? street;
final String? country;
final String? zipCode;
@override
List<Object?> get props => <Object?>[

View File

@@ -4,13 +4,13 @@ import 'package:krow_core/core.dart';
///
/// Encapsulates the hub ID of the hub to be deleted.
class DeleteHubArguments extends UseCaseArgument {
/// The unique identifier of the hub to delete.
final String hubId;
/// Creates a [DeleteHubArguments] instance.
///
/// The [hubId] is required.
const DeleteHubArguments({required this.hubId});
/// The unique identifier of the hub to delete.
final String hubId;
@override
List<Object?> get props => <Object?>[hubId];

View File

@@ -7,12 +7,12 @@ import '../repositories/hub_repository_interface.dart';
/// This use case handles the association of a physical NFC tag with a specific
/// hub by calling the [HubRepositoryInterface].
class AssignNfcTagUseCase implements UseCase<AssignNfcTagArguments, void> {
final HubRepositoryInterface _repository;
/// Creates an [AssignNfcTagUseCase].
///
/// Requires a [HubRepositoryInterface] to interact with the backend.
AssignNfcTagUseCase(this._repository);
final HubRepositoryInterface _repository;
@override
Future<void> call(AssignNfcTagArguments arguments) {

View File

@@ -9,12 +9,12 @@ import '../repositories/hub_repository_interface.dart';
/// [HubRepositoryInterface]. It requires [CreateHubArguments] which includes
/// the name and address of the hub.
class CreateHubUseCase implements UseCase<CreateHubArguments, Hub> {
final HubRepositoryInterface _repository;
/// Creates a [CreateHubUseCase].
///
/// Requires a [HubRepositoryInterface] to perform the actual creation.
CreateHubUseCase(this._repository);
final HubRepositoryInterface _repository;
@override
Future<Hub> call(CreateHubArguments arguments) {

View File

@@ -6,12 +6,12 @@ import '../repositories/hub_repository_interface.dart';
///
/// This use case removes a hub from the system via the [HubRepositoryInterface].
class DeleteHubUseCase implements UseCase<DeleteHubArguments, void> {
final HubRepositoryInterface _repository;
/// Creates a [DeleteHubUseCase].
///
/// Requires a [HubRepositoryInterface] to perform the deletion.
DeleteHubUseCase(this._repository);
final HubRepositoryInterface _repository;
@override
Future<void> call(DeleteHubArguments arguments) {

View File

@@ -7,12 +7,12 @@ import '../repositories/hub_repository_interface.dart';
/// This use case retrieves all hubs associated with the current client
/// by interacting with the [HubRepositoryInterface].
class GetHubsUseCase implements NoInputUseCase<List<Hub>> {
final HubRepositoryInterface _repository;
/// Creates a [GetHubsUseCase].
///
/// Requires a [HubRepositoryInterface] to fetch the data.
GetHubsUseCase(this._repository);
final HubRepositoryInterface _repository;
@override
Future<List<Hub>> call() {

View File

@@ -19,10 +19,6 @@ import 'client_hubs_state.dart';
class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
with BlocErrorHandler<ClientHubsState>
implements Disposable {
final GetHubsUseCase _getHubsUseCase;
final CreateHubUseCase _createHubUseCase;
final DeleteHubUseCase _deleteHubUseCase;
final AssignNfcTagUseCase _assignNfcTagUseCase;
ClientHubsBloc({
required GetHubsUseCase getHubsUseCase,
@@ -42,6 +38,10 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
on<ClientHubsAddDialogToggled>(_onAddDialogToggled);
on<ClientHubsIdentifyDialogToggled>(_onIdentifyDialogToggled);
}
final GetHubsUseCase _getHubsUseCase;
final CreateHubUseCase _createHubUseCase;
final DeleteHubUseCase _deleteHubUseCase;
final AssignNfcTagUseCase _assignNfcTagUseCase;
void _onAddDialogToggled(
ClientHubsAddDialogToggled event,
@@ -70,10 +70,10 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
await handleError(
emit: emit,
action: () async {
final hubs = await _getHubsUseCase();
final List<Hub> hubs = await _getHubsUseCase();
emit(state.copyWith(status: ClientHubsStatus.success, hubs: hubs));
},
onError: (errorKey) => state.copyWith(
onError: (String errorKey) => state.copyWith(
status: ClientHubsStatus.failure,
errorMessage: errorKey,
),
@@ -103,7 +103,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
zipCode: event.zipCode,
),
);
final hubs = await _getHubsUseCase();
final List<Hub> hubs = await _getHubsUseCase();
emit(
state.copyWith(
status: ClientHubsStatus.actionSuccess,
@@ -113,7 +113,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
),
);
},
onError: (errorKey) => state.copyWith(
onError: (String errorKey) => state.copyWith(
status: ClientHubsStatus.actionFailure,
errorMessage: errorKey,
),
@@ -130,7 +130,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
emit: emit,
action: () async {
await _deleteHubUseCase(DeleteHubArguments(hubId: event.hubId));
final hubs = await _getHubsUseCase();
final List<Hub> hubs = await _getHubsUseCase();
emit(
state.copyWith(
status: ClientHubsStatus.actionSuccess,
@@ -139,7 +139,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
),
);
},
onError: (errorKey) => state.copyWith(
onError: (String errorKey) => state.copyWith(
status: ClientHubsStatus.actionFailure,
errorMessage: errorKey,
),
@@ -158,7 +158,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
await _assignNfcTagUseCase(
AssignNfcTagArguments(hubId: event.hubId, nfcTagId: event.nfcTagId),
);
final hubs = await _getHubsUseCase();
final List<Hub> hubs = await _getHubsUseCase();
emit(
state.copyWith(
status: ClientHubsStatus.actionSuccess,
@@ -168,7 +168,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
),
);
},
onError: (errorKey) => state.copyWith(
onError: (String errorKey) => state.copyWith(
status: ClientHubsStatus.actionFailure,
errorMessage: errorKey,
),

View File

@@ -16,16 +16,6 @@ class ClientHubsFetched extends ClientHubsEvent {
/// Event triggered to add a new hub.
class ClientHubsAddRequested extends ClientHubsEvent {
final String name;
final String address;
final String? placeId;
final double? latitude;
final double? longitude;
final String? city;
final String? state;
final String? street;
final String? country;
final String? zipCode;
const ClientHubsAddRequested({
required this.name,
@@ -39,6 +29,16 @@ class ClientHubsAddRequested extends ClientHubsEvent {
this.country,
this.zipCode,
});
final String name;
final String address;
final String? placeId;
final double? latitude;
final double? longitude;
final String? city;
final String? state;
final String? street;
final String? country;
final String? zipCode;
@override
List<Object?> get props => <Object?>[
@@ -57,9 +57,9 @@ class ClientHubsAddRequested extends ClientHubsEvent {
/// Event triggered to delete a hub.
class ClientHubsDeleteRequested extends ClientHubsEvent {
final String hubId;
const ClientHubsDeleteRequested(this.hubId);
final String hubId;
@override
List<Object?> get props => <Object?>[hubId];
@@ -67,13 +67,13 @@ class ClientHubsDeleteRequested extends ClientHubsEvent {
/// Event triggered to assign an NFC tag to a hub.
class ClientHubsNfcTagAssignRequested extends ClientHubsEvent {
final String hubId;
final String nfcTagId;
const ClientHubsNfcTagAssignRequested({
required this.hubId,
required this.nfcTagId,
});
final String hubId;
final String nfcTagId;
@override
List<Object?> get props => <Object?>[hubId, nfcTagId];
@@ -86,9 +86,9 @@ class ClientHubsMessageCleared extends ClientHubsEvent {
/// Event triggered to toggle the visibility of the "Add Hub" dialog.
class ClientHubsAddDialogToggled extends ClientHubsEvent {
final bool visible;
const ClientHubsAddDialogToggled({required this.visible});
final bool visible;
@override
List<Object?> get props => <Object?>[visible];
@@ -96,9 +96,9 @@ class ClientHubsAddDialogToggled extends ClientHubsEvent {
/// Event triggered to toggle the visibility of the "Identify NFC" dialog.
class ClientHubsIdentifyDialogToggled extends ClientHubsEvent {
final Hub? hub;
const ClientHubsIdentifyDialogToggled({this.hub});
final Hub? hub;
@override
List<Object?> get props => <Object?>[hub];

View File

@@ -14,6 +14,15 @@ enum ClientHubsStatus {
/// State class for the ClientHubs BLoC.
class ClientHubsState extends Equatable {
const ClientHubsState({
this.status = ClientHubsStatus.initial,
this.hubs = const <Hub>[],
this.errorMessage,
this.successMessage,
this.showAddHubDialog = false,
this.hubToIdentify,
});
final ClientHubsStatus status;
final List<Hub> hubs;
final String? errorMessage;
@@ -26,15 +35,6 @@ class ClientHubsState extends Equatable {
/// If null, the identification dialog is closed.
final Hub? hubToIdentify;
const ClientHubsState({
this.status = ClientHubsStatus.initial,
this.hubs = const <Hub>[],
this.errorMessage,
this.successMessage,
this.showAddHubDialog = false,
this.hubToIdentify,
});
ClientHubsState copyWith({
ClientHubsStatus? status,
List<Hub>? hubs,

View File

@@ -7,6 +7,13 @@ import 'hub_address_autocomplete.dart';
/// A dialog for adding a new hub.
class AddHubDialog extends StatefulWidget {
/// Creates an [AddHubDialog].
const AddHubDialog({
required this.onCreate,
required this.onCancel,
super.key,
});
/// Callback when the "Create Hub" button is pressed.
final void Function(
String name,
@@ -19,13 +26,6 @@ class AddHubDialog extends StatefulWidget {
/// Callback when the dialog is cancelled.
final VoidCallback onCancel;
/// Creates an [AddHubDialog].
const AddHubDialog({
required this.onCreate,
required this.onCancel,
super.key,
});
@override
State<AddHubDialog> createState() => _AddHubDialogState();
}

View File

@@ -39,7 +39,7 @@ class HubAddressAutocomplete extends StatelessWidget {
);
onSelected?.call(prediction);
},
itemBuilder: (_, _, Prediction prediction) {
itemBuilder: (BuildContext context, int index, Prediction prediction) {
return Padding(
padding: const EdgeInsets.all(UiConstants.space2),
child: Row(

View File

@@ -5,14 +5,6 @@ import 'package:core_localization/core_localization.dart';
/// A card displaying information about a single hub.
class HubCard extends StatelessWidget {
/// The hub to display.
final Hub hub;
/// Callback when the NFC button is pressed.
final VoidCallback onNfcPressed;
/// Callback when the delete button is pressed.
final VoidCallback onDeletePressed;
/// Creates a [HubCard].
const HubCard({
@@ -21,6 +13,14 @@ class HubCard extends StatelessWidget {
required this.onDeletePressed,
super.key,
});
/// The hub to display.
final Hub hub;
/// Callback when the NFC button is pressed.
final VoidCallback onNfcPressed;
/// Callback when the delete button is pressed.
final VoidCallback onDeletePressed;
@override
Widget build(BuildContext context) {

View File

@@ -4,11 +4,11 @@ import 'package:core_localization/core_localization.dart';
/// Widget displayed when there are no hubs.
class HubEmptyState extends StatelessWidget {
/// Callback when the add button is pressed.
final VoidCallback onAddPressed;
/// Creates a [HubEmptyState].
const HubEmptyState({required this.onAddPressed, super.key});
/// Callback when the add button is pressed.
final VoidCallback onAddPressed;
@override
Widget build(BuildContext context) {

View File

@@ -5,14 +5,6 @@ import 'package:core_localization/core_localization.dart';
/// A dialog for identifying and assigning an NFC tag to a hub.
class IdentifyNfcDialog extends StatefulWidget {
/// The hub to assign the tag to.
final Hub hub;
/// Callback when a tag is assigned.
final Function(String nfcTagId) onAssign;
/// Callback when the dialog is cancelled.
final VoidCallback onCancel;
/// Creates an [IdentifyNfcDialog].
const IdentifyNfcDialog({
@@ -21,6 +13,14 @@ class IdentifyNfcDialog extends StatefulWidget {
required this.onCancel,
super.key,
});
/// The hub to assign the tag to.
final Hub hub;
/// Callback when a tag is assigned.
final Function(String nfcTagId) onAssign;
/// Callback when the dialog is cancelled.
final VoidCallback onCancel;
@override
State<IdentifyNfcDialog> createState() => _IdentifyNfcDialogState();