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

@@ -25,7 +25,6 @@ class ClientHomeModule extends Module {
// Repositories
i.addLazySingleton<HomeRepositoryInterface>(
() => HomeRepositoryImpl(
i.get<HomeRepositoryMock>(),
ExampleConnector.instance,
),
);

View File

@@ -1,5 +1,5 @@
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/home_repository_interface.dart';
@@ -8,17 +8,14 @@ import '../../domain/repositories/home_repository_interface.dart';
/// This implementation resides in the data layer and acts as a bridge between the
/// domain layer and the data source (in this case, a mock from data_connect).
class HomeRepositoryImpl implements HomeRepositoryInterface {
final HomeRepositoryMock _mock;
final ExampleConnector _dataConnect;
/// Creates a [HomeRepositoryImpl].
///
/// Requires a [HomeRepositoryMock] to perform data operations.
HomeRepositoryImpl(this._mock, this._dataConnect);
HomeRepositoryImpl(this._dataConnect);
final dc.ExampleConnector _dataConnect;
@override
Future<HomeDashboardData> getDashboardData() async {
final String? businessId = ClientSessionStore.instance.session?.business?.id;
final String? businessId = dc.ClientSessionStore.instance.session?.business?.id;
if (businessId == null || businessId.isEmpty) {
return const HomeDashboardData(
weeklySpending: 0,
@@ -38,8 +35,8 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
final DateTime weekRangeEnd =
DateTime(monday.year, monday.month, monday.day + 13, 23, 59, 59, 999);
final fdc.QueryResult<
GetCompletedShiftsByBusinessIdData,
GetCompletedShiftsByBusinessIdVariables> completedResult =
dc.GetCompletedShiftsByBusinessIdData,
dc.GetCompletedShiftsByBusinessIdVariables> completedResult =
await _dataConnect
.getCompletedShiftsByBusinessId(
businessId: businessId,
@@ -47,16 +44,13 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
dateTo: _toTimestamp(weekRangeEnd),
)
.execute();
print(
'Home spending: businessId=$businessId dateFrom=${weekRangeStart.toIso8601String()} '
'dateTo=${weekRangeEnd.toIso8601String()} shifts=${completedResult.data.shifts.length}',
);
double weeklySpending = 0.0;
double next7DaysSpending = 0.0;
int weeklyShifts = 0;
int next7DaysScheduled = 0;
for (final GetCompletedShiftsByBusinessIdShifts shift
for (final dc.GetCompletedShiftsByBusinessIdShifts shift
in completedResult.data.shifts) {
final DateTime? shiftDate = shift.date?.toDateTime();
if (shiftDate == null) {
@@ -80,8 +74,8 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
final DateTime end = DateTime(now.year, now.month, now.day, 23, 59, 59, 999);
final fdc.QueryResult<
ListShiftRolesByBusinessAndDateRangeData,
ListShiftRolesByBusinessAndDateRangeVariables> result =
dc.ListShiftRolesByBusinessAndDateRangeData,
dc.ListShiftRolesByBusinessAndDateRangeVariables> result =
await _dataConnect
.listShiftRolesByBusinessAndDateRange(
businessId: businessId,
@@ -89,18 +83,11 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
end: _toTimestamp(end),
)
.execute();
print(
'Home coverage: businessId=$businessId '
'startLocal=${start.toIso8601String()} '
'endLocal=${end.toIso8601String()} '
'startUtc=${_toTimestamp(start).toJson()} '
'endUtc=${_toTimestamp(end).toJson()} '
'shiftRoles=${result.data.shiftRoles.length}',
);
int totalNeeded = 0;
int totalFilled = 0;
for (final ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole
for (final dc.ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole
in result.data.shiftRoles) {
totalNeeded += shiftRole.count;
totalFilled += shiftRole.assigned ?? 0;
@@ -118,16 +105,16 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
@override
UserSessionData getUserSessionData() {
final (String businessName, String? photoUrl) = _mock.getUserSession();
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
return UserSessionData(
businessName: businessName,
photoUrl: photoUrl,
businessName: session?.business?.businessName ?? '',
photoUrl: null, // Business photo isn't currently in session
);
}
@override
Future<List<ReorderItem>> getRecentReorders() async {
final String? businessId = ClientSessionStore.instance.session?.business?.id;
final String? businessId = dc.ClientSessionStore.instance.session?.business?.id;
if (businessId == null || businessId.isEmpty) {
return const <ReorderItem>[];
}
@@ -138,27 +125,20 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
final fdc.Timestamp endTimestamp = _toTimestamp(now);
final fdc.QueryResult<
ListShiftRolesByBusinessDateRangeCompletedOrdersData,
ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> result =
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersData,
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> result =
await _dataConnect.listShiftRolesByBusinessDateRangeCompletedOrders(
businessId: businessId,
start: startTimestamp,
end: endTimestamp,
).execute();
print(
'Home reorder: completed shiftRoles=${result.data.shiftRoles.length}',
);
return result.data.shiftRoles.map((
ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles shiftRole,
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles shiftRole,
) {
print(
'Home reorder item: orderId=${shiftRole.shift.order.id} '
'shiftId=${shiftRole.shiftId} roleId=${shiftRole.roleId} '
'orderType=${shiftRole.shift.order.orderType.stringValue} '
'hours=${shiftRole.hours} count=${shiftRole.count}',
);
final String location =
shiftRole.shift.location ??
shiftRole.shift.locationAddress ??

View File

@@ -2,17 +2,17 @@ import 'package:krow_domain/krow_domain.dart';
/// User session data for the home page.
class UserSessionData {
/// The business name of the logged-in user.
final String businessName;
/// The photo URL of the logged-in user (optional).
final String? photoUrl;
/// Creates a [UserSessionData].
const UserSessionData({
required this.businessName,
this.photoUrl,
});
/// The business name of the logged-in user.
final String businessName;
/// The photo URL of the logged-in user (optional).
final String? photoUrl;
}
/// Interface for the Client Home repository.

View File

@@ -7,10 +7,10 @@ import '../repositories/home_repository_interface.dart';
/// This use case coordinates with the [HomeRepositoryInterface] to retrieve
/// the [HomeDashboardData] required for the dashboard display.
class GetDashboardDataUseCase implements NoInputUseCase<HomeDashboardData> {
final HomeRepositoryInterface _repository;
/// Creates a [GetDashboardDataUseCase].
GetDashboardDataUseCase(this._repository);
final HomeRepositoryInterface _repository;
@override
Future<HomeDashboardData> call() {

View File

@@ -4,10 +4,10 @@ import '../repositories/home_repository_interface.dart';
/// Use case to fetch recent completed shift roles for reorder suggestions.
class GetRecentReordersUseCase implements NoInputUseCase<List<ReorderItem>> {
final HomeRepositoryInterface _repository;
/// Creates a [GetRecentReordersUseCase].
GetRecentReordersUseCase(this._repository);
final HomeRepositoryInterface _repository;
@override
Future<List<ReorderItem>> call() {

View File

@@ -4,10 +4,10 @@ import '../repositories/home_repository_interface.dart';
///
/// Returns the user's business name and photo URL for display in the header.
class GetUserSessionDataUseCase {
final HomeRepositoryInterface _repository;
/// Creates a [GetUserSessionDataUseCase].
GetUserSessionDataUseCase(this._repository);
final HomeRepositoryInterface _repository;
/// Executes the use case to get session data.
UserSessionData call() {

View File

@@ -9,9 +9,6 @@ import 'client_home_state.dart';
/// BLoC responsible for managing the state and business logic of the client home dashboard.
class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
final GetDashboardDataUseCase _getDashboardDataUseCase;
final GetRecentReordersUseCase _getRecentReordersUseCase;
final GetUserSessionDataUseCase _getUserSessionDataUseCase;
ClientHomeBloc({
required GetDashboardDataUseCase getDashboardDataUseCase,
@@ -29,6 +26,9 @@ class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
add(ClientHomeStarted());
}
final GetDashboardDataUseCase _getDashboardDataUseCase;
final GetRecentReordersUseCase _getRecentReordersUseCase;
final GetUserSessionDataUseCase _getUserSessionDataUseCase;
Future<void> _onStarted(
ClientHomeStarted event,
@@ -83,7 +83,7 @@ class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState> {
Emitter<ClientHomeState> emit,
) {
final List<String> newList = List<String>.from(state.widgetOrder);
int oldIndex = event.oldIndex;
final int oldIndex = event.oldIndex;
int newIndex = event.newIndex;
if (oldIndex < newIndex) {

View File

@@ -12,17 +12,17 @@ class ClientHomeStarted extends ClientHomeEvent {}
class ClientHomeEditModeToggled extends ClientHomeEvent {}
class ClientHomeWidgetVisibilityToggled extends ClientHomeEvent {
final String widgetId;
const ClientHomeWidgetVisibilityToggled(this.widgetId);
final String widgetId;
@override
List<Object?> get props => <Object?>[widgetId];
}
class ClientHomeWidgetReordered extends ClientHomeEvent {
const ClientHomeWidgetReordered(this.oldIndex, this.newIndex);
final int oldIndex;
final int newIndex;
const ClientHomeWidgetReordered(this.oldIndex, this.newIndex);
@override
List<Object?> get props => <Object?>[oldIndex, newIndex];

View File

@@ -6,15 +6,6 @@ enum ClientHomeStatus { initial, loading, success, error }
/// Represents the state of the client home dashboard.
class ClientHomeState extends Equatable {
final ClientHomeStatus status;
final List<String> widgetOrder;
final Map<String, bool> widgetVisibility;
final bool isEditMode;
final String? errorMessage;
final HomeDashboardData dashboardData;
final List<ReorderItem> reorderItems;
final String businessName;
final String? photoUrl;
const ClientHomeState({
this.status = ClientHomeStatus.initial,
@@ -46,6 +37,15 @@ class ClientHomeState extends Equatable {
this.businessName = 'Your Company',
this.photoUrl,
});
final ClientHomeStatus status;
final List<String> widgetOrder;
final Map<String, bool> widgetVisibility;
final bool isEditMode;
final String? errorMessage;
final HomeDashboardData dashboardData;
final List<ReorderItem> reorderItems;
final String businessName;
final String? photoUrl;
ClientHomeState copyWith({
ClientHomeStatus? status,

View File

@@ -4,14 +4,6 @@ import 'package:flutter/material.dart';
/// A widget that displays quick actions for the client.
class ActionsWidget extends StatelessWidget {
/// Callback when RAPID is pressed.
final VoidCallback onRapidPressed;
/// Callback when Create Order is pressed.
final VoidCallback onCreateOrderPressed;
/// Optional subtitle for the section.
final String? subtitle;
/// Creates an [ActionsWidget].
const ActionsWidget({
@@ -20,6 +12,14 @@ class ActionsWidget extends StatelessWidget {
required this.onCreateOrderPressed,
this.subtitle,
});
/// Callback when RAPID is pressed.
final VoidCallback onRapidPressed;
/// Callback when Create Order is pressed.
final VoidCallback onCreateOrderPressed;
/// Optional subtitle for the section.
final String? subtitle;
@override
Widget build(BuildContext context) {
@@ -69,16 +69,6 @@ class ActionsWidget extends StatelessWidget {
}
class _ActionCard extends StatelessWidget {
final String title;
final String subtitle;
final IconData icon;
final Color color;
final Color borderColor;
final Color iconBgColor;
final Color iconColor;
final Color textColor;
final Color subtitleColor;
final VoidCallback onTap;
const _ActionCard({
required this.title,
@@ -92,6 +82,16 @@ class _ActionCard extends StatelessWidget {
required this.subtitleColor,
required this.onTap,
});
final String title;
final String subtitle;
final IconData icon;
final Color color;
final Color borderColor;
final Color iconBgColor;
final Color iconColor;
final Color textColor;
final Color subtitleColor;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {

View File

@@ -10,14 +10,14 @@ import '../blocs/client_home_state.dart';
/// Shows instructions for reordering widgets and provides a reset button
/// to restore the default layout.
class ClientHomeEditBanner extends StatelessWidget {
/// The internationalization object for localized strings.
final dynamic i18n;
/// Creates a [ClientHomeEditBanner].
const ClientHomeEditBanner({
required this.i18n,
super.key,
});
/// The internationalization object for localized strings.
final dynamic i18n;
@override
Widget build(BuildContext context) {

View File

@@ -13,14 +13,14 @@ import 'header_icon_button.dart';
/// Displays the user's business name, avatar, and action buttons
/// (edit mode, notifications, settings).
class ClientHomeHeader extends StatelessWidget {
/// The internationalization object for localized strings.
final dynamic i18n;
/// Creates a [ClientHomeHeader].
const ClientHomeHeader({
required this.i18n,
super.key,
});
/// The internationalization object for localized strings.
final dynamic i18n;
@override
Widget build(BuildContext context) {

View File

@@ -3,11 +3,6 @@ import 'package:flutter/material.dart';
/// A dashboard widget that displays today's coverage status.
class CoverageDashboard extends StatelessWidget {
/// The list of shifts for today.
final List<dynamic> shifts;
/// The list of applications for today's shifts.
final List<dynamic> applications;
/// Creates a [CoverageDashboard].
const CoverageDashboard({
@@ -15,6 +10,11 @@ class CoverageDashboard extends StatelessWidget {
required this.shifts,
required this.applications,
});
/// The list of shifts for today.
final List<dynamic> shifts;
/// The list of applications for today's shifts.
final List<dynamic> applications;
@override
Widget build(BuildContext context) {
@@ -145,12 +145,6 @@ class CoverageDashboard extends StatelessWidget {
}
class _StatusCard extends StatelessWidget {
final String label;
final String value;
final IconData icon;
final bool isWarning;
final bool isError;
final bool isInfo;
const _StatusCard({
required this.label,
@@ -160,6 +154,12 @@ class _StatusCard extends StatelessWidget {
this.isError = false,
this.isInfo = false,
});
final String label;
final String value;
final IconData icon;
final bool isWarning;
final bool isError;
final bool isInfo;
@override
Widget build(BuildContext context) {

View File

@@ -3,6 +3,15 @@ import 'package:flutter/material.dart';
/// A widget that displays the daily coverage metrics.
class CoverageWidget extends StatelessWidget {
/// Creates a [CoverageWidget].
const CoverageWidget({
super.key,
this.totalNeeded = 0,
this.totalConfirmed = 0,
this.coveragePercent = 0,
this.subtitle,
});
/// The total number of shifts needed.
final int totalNeeded;
@@ -15,15 +24,6 @@ class CoverageWidget extends StatelessWidget {
/// Optional subtitle for the section.
final String? subtitle;
/// Creates a [CoverageWidget].
const CoverageWidget({
super.key,
this.totalNeeded = 0,
this.totalConfirmed = 0,
this.coveragePercent = 0,
this.subtitle,
});
@override
Widget build(BuildContext context) {
Color backgroundColor;
@@ -114,11 +114,6 @@ class CoverageWidget extends StatelessWidget {
}
class _MetricCard extends StatelessWidget {
final IconData icon;
final Color iconColor;
final String label;
final String value;
final Color? valueColor;
const _MetricCard({
required this.icon,
@@ -127,6 +122,11 @@ class _MetricCard extends StatelessWidget {
required this.value,
this.valueColor,
});
final IconData icon;
final Color iconColor;
final String label;
final String value;
final Color? valueColor;
@override
Widget build(BuildContext context) {

View File

@@ -16,14 +16,6 @@ import 'client_home_sheets.dart';
/// This widget encapsulates the logic for rendering different dashboard
/// widgets based on their unique identifiers and current state.
class DashboardWidgetBuilder extends StatelessWidget {
/// The unique identifier for the widget to build.
final String id;
/// The current dashboard state.
final ClientHomeState state;
/// Whether the widget is in edit mode.
final bool isEditMode;
/// Creates a [DashboardWidgetBuilder].
const DashboardWidgetBuilder({
@@ -32,6 +24,14 @@ class DashboardWidgetBuilder extends StatelessWidget {
required this.isEditMode,
super.key,
});
/// The unique identifier for the widget to build.
final String id;
/// The current dashboard state.
final ClientHomeState state;
/// Whether the widget is in edit mode.
final bool isEditMode;
@override
Widget build(BuildContext context) {

View File

@@ -9,6 +9,15 @@ import '../blocs/client_home_event.dart';
/// Displays drag handles, visibility toggles, and wraps the actual widget
/// content with appropriate styling for the edit state.
class DraggableWidgetWrapper extends StatelessWidget {
/// Creates a [DraggableWidgetWrapper].
const DraggableWidgetWrapper({
required this.id,
required this.title,
required this.child,
required this.isVisible,
super.key,
});
/// The unique identifier for this widget.
final String id;
@@ -21,15 +30,6 @@ class DraggableWidgetWrapper extends StatelessWidget {
/// Whether this widget is currently visible.
final bool isVisible;
/// Creates a [DraggableWidgetWrapper].
const DraggableWidgetWrapper({
required this.id,
required this.title,
required this.child,
required this.isVisible,
super.key,
});
@override
Widget build(BuildContext context) {
return Column(

View File

@@ -6,6 +6,15 @@ import 'package:flutter/material.dart';
/// Supports an optional badge for notification counts and an active state
/// for toggled actions.
class HeaderIconButton extends StatelessWidget {
/// Creates a [HeaderIconButton].
const HeaderIconButton({
required this.icon,
this.badgeText,
this.isActive = false,
required this.onTap,
super.key,
});
/// The icon to display.
final IconData icon;
@@ -18,15 +27,6 @@ class HeaderIconButton extends StatelessWidget {
/// Callback invoked when the button is tapped.
final VoidCallback onTap;
/// Creates a [HeaderIconButton].
const HeaderIconButton({
required this.icon,
this.badgeText,
this.isActive = false,
required this.onTap,
super.key,
});
@override
Widget build(BuildContext context) {
return GestureDetector(

View File

@@ -7,11 +7,6 @@ import 'coverage_dashboard.dart';
/// A widget that displays live activity information.
class LiveActivityWidget extends StatefulWidget {
/// Callback when "View all" is pressed.
final VoidCallback onViewAllPressed;
/// Optional subtitle for the section.
final String? subtitle;
/// Creates a [LiveActivityWidget].
const LiveActivityWidget({
@@ -19,6 +14,11 @@ class LiveActivityWidget extends StatefulWidget {
required this.onViewAllPressed,
this.subtitle
});
/// Callback when "View all" is pressed.
final VoidCallback onViewAllPressed;
/// Optional subtitle for the section.
final String? subtitle;
@override
State<LiveActivityWidget> createState() => _LiveActivityWidgetState();
@@ -178,6 +178,16 @@ class _LiveActivityWidgetState extends State<LiveActivityWidget> {
}
class _LiveActivityData {
factory _LiveActivityData.empty() {
return const _LiveActivityData(
totalNeeded: 0,
totalAssigned: 0,
totalCost: 0,
checkedInCount: 0,
lateCount: 0,
);
}
const _LiveActivityData({
required this.totalNeeded,
required this.totalAssigned,
@@ -191,14 +201,4 @@ class _LiveActivityData {
final double totalCost;
final int checkedInCount;
final int lateCount;
factory _LiveActivityData.empty() {
return const _LiveActivityData(
totalNeeded: 0,
totalAssigned: 0,
totalCost: 0,
checkedInCount: 0,
lateCount: 0,
);
}
}

View File

@@ -5,14 +5,6 @@ import 'package:krow_domain/krow_domain.dart';
/// A widget that allows clients to reorder recent shifts.
class ReorderWidget extends StatelessWidget {
/// Recent completed orders for reorder.
final List<ReorderItem> orders;
/// Callback when a reorder button is pressed.
final Function(Map<String, dynamic> shiftData) onReorderPressed;
/// Optional subtitle for the section.
final String? subtitle;
/// Creates a [ReorderWidget].
const ReorderWidget({
@@ -21,6 +13,14 @@ class ReorderWidget extends StatelessWidget {
required this.onReorderPressed,
this.subtitle,
});
/// Recent completed orders for reorder.
final List<ReorderItem> orders;
/// Callback when a reorder button is pressed.
final Function(Map<String, dynamic> shiftData) onReorderPressed;
/// Optional subtitle for the section.
final String? subtitle;
@override
Widget build(BuildContext context) {
@@ -177,11 +177,6 @@ class ReorderWidget extends StatelessWidget {
}
class _Badge extends StatelessWidget {
final IconData icon;
final String text;
final Color color;
final Color bg;
final Color textColor;
const _Badge({
required this.icon,
@@ -190,6 +185,11 @@ class _Badge extends StatelessWidget {
required this.bg,
required this.textColor,
});
final IconData icon;
final String text;
final Color color;
final Color bg;
final Color textColor;
@override
Widget build(BuildContext context) {

View File

@@ -29,14 +29,6 @@ class _VendorOption {
/// This widget provides a comprehensive form matching the design patterns
/// used in view_order_card.dart for consistency across the app.
class ShiftOrderFormSheet extends StatefulWidget {
/// Initial data for the form (e.g. from a reorder action).
final Map<String, dynamic>? initialData;
/// Callback when the form is submitted.
final Function(Map<String, dynamic> data) onSubmit;
/// Whether the submission is loading.
final bool isLoading;
/// Creates a [ShiftOrderFormSheet].
const ShiftOrderFormSheet({
@@ -45,6 +37,14 @@ class ShiftOrderFormSheet extends StatefulWidget {
required this.onSubmit,
this.isLoading = false,
});
/// Initial data for the form (e.g. from a reorder action).
final Map<String, dynamic>? initialData;
/// Callback when the form is submitted.
final Function(Map<String, dynamic> data) onSubmit;
/// Whether the submission is loading.
final bool isLoading;
@override
State<ShiftOrderFormSheet> createState() => _ShiftOrderFormSheetState();
@@ -222,10 +222,7 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
.date(orderTimestamp)
.execute();
final String? orderId = orderResult.data?.order_insert.id;
if (orderId == null) {
return;
}
final String orderId = orderResult.data.order_insert.id;
final int workersNeeded = _positions.fold<int>(
0,
@@ -255,10 +252,7 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
.cost(shiftCost)
.execute();
final String? shiftId = shiftResult.data?.shift_insert.id;
if (shiftId == null) {
return;
}
final String shiftId = shiftResult.data.shift_insert.id;
for (final Map<String, dynamic> pos in _positions) {
final String roleId = pos['roleId']?.toString() ?? '';
@@ -415,12 +409,12 @@ class _ShiftOrderFormSheetState extends State<ShiftOrderFormSheet> {
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShift firstShift =
shiftRoles.first.shift;
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShiftOrderTeamHub?
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShiftOrderTeamHub
teamHub = firstShift.order.teamHub;
await _loadHubsAndSelect(
placeId: teamHub?.placeId,
hubName: teamHub?.hubName,
address: teamHub?.address,
placeId: teamHub.placeId,
hubName: teamHub.hubName,
address: teamHub.address,
);
_orderNameController.text = firstShift.order.eventName ?? '';

View File

@@ -4,6 +4,16 @@ import 'package:flutter/material.dart';
/// A widget that displays spending insights for the client.
class SpendingWidget extends StatelessWidget {
/// Creates a [SpendingWidget].
const SpendingWidget({
super.key,
required this.weeklySpending,
required this.next7DaysSpending,
required this.weeklyShifts,
required this.next7DaysScheduled,
this.subtitle,
});
/// The spending this week.
final double weeklySpending;
@@ -19,16 +29,6 @@ class SpendingWidget extends StatelessWidget {
/// Optional subtitle for the section.
final String? subtitle;
/// Creates a [SpendingWidget].
const SpendingWidget({
super.key,
required this.weeklySpending,
required this.next7DaysSpending,
required this.weeklyShifts,
required this.next7DaysScheduled,
this.subtitle,
});
@override
Widget build(BuildContext context) {
final TranslationsClientHomeEn i18n = t.client_home;

View File

@@ -23,7 +23,11 @@ dependencies:
path: ../../../core_localization
krow_domain: ^0.0.1
krow_data_connect: ^0.0.1
krow_core:
path: ../../../core
firebase_data_connect: any
intl: any
dev_dependencies:
flutter_test:
sdk: flutter