From 61d7c08c955354b037b24b68e2c8e4d573c4726f Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Wed, 21 Jan 2026 20:11:09 -0500 Subject: [PATCH] feat: Implement Hubs feature with dedicated navigation, a home page action card, a settings quick link, and localization. --- apps/apps/client/lib/main.dart | 2 ++ apps/apps/client/pubspec.yaml | 2 ++ .../lib/src/l10n/en.i18n.json | 4 +++- .../lib/src/l10n/es.i18n.json | 4 +++- .../lib/src/l10n/strings.g.dart | 4 ++-- .../lib/src/l10n/strings_en.g.dart | 8 ++++++++ .../lib/src/l10n/strings_es.g.dart | 4 ++++ .../lib/src/data_connect_module.dart | 4 +++- .../navigation/client_home_navigator.dart | 5 +++++ .../presentation/pages/client_home_page.dart | 1 + .../presentation/widgets/actions_widget.dart | 19 +++++++++++++++++++ .../navigation/client_hubs_navigator.dart | 2 +- .../presentation/pages/client_hubs_page.dart | 4 ++++ .../navigation/client_settings_navigator.dart | 5 +++++ .../settings_quick_links.dart | 4 +++- 15 files changed, 65 insertions(+), 7 deletions(-) diff --git a/apps/apps/client/lib/main.dart b/apps/apps/client/lib/main.dart index f23426e2..03e1142b 100644 --- a/apps/apps/client/lib/main.dart +++ b/apps/apps/client/lib/main.dart @@ -8,6 +8,7 @@ import 'package:client_authentication/client_authentication.dart' as client_authentication; import 'package:client_home/client_home.dart' as client_home; import 'package:client_settings/client_settings.dart' as client_settings; +import 'package:client_hubs/client_hubs.dart' as client_hubs; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -32,6 +33,7 @@ class AppModule extends Module { '/client-settings', module: client_settings.ClientSettingsModule(), ); + r.module('/client/hubs', module: client_hubs.ClientHubsModule()); } } diff --git a/apps/apps/client/pubspec.yaml b/apps/apps/client/pubspec.yaml index e969060a..edbf3c43 100644 --- a/apps/apps/client/pubspec.yaml +++ b/apps/apps/client/pubspec.yaml @@ -21,6 +21,8 @@ dependencies: path: ../../packages/features/client/settings core_localization: path: ../../packages/core_localization + client_hubs: + path: ../../packages/features/client/hubs flutter_modular: ^6.3.2 flutter_bloc: ^8.1.3 flutter_localizations: diff --git a/apps/packages/core_localization/lib/src/l10n/en.i18n.json b/apps/packages/core_localization/lib/src/l10n/en.i18n.json index 01ba7faf..b31c4a4c 100644 --- a/apps/packages/core_localization/lib/src/l10n/en.i18n.json +++ b/apps/packages/core_localization/lib/src/l10n/en.i18n.json @@ -160,7 +160,9 @@ "rapid": "RAPID", "rapid_subtitle": "Urgent same-day", "create_order": "Create Order", - "create_order_subtitle": "Schedule shifts" + "create_order_subtitle": "Schedule shifts", + "hubs": "Hubs", + "hubs_subtitle": "Clock-in points" }, "reorder": { "title": "REORDER", diff --git a/apps/packages/core_localization/lib/src/l10n/es.i18n.json b/apps/packages/core_localization/lib/src/l10n/es.i18n.json index b114e2ad..6561ef02 100644 --- a/apps/packages/core_localization/lib/src/l10n/es.i18n.json +++ b/apps/packages/core_localization/lib/src/l10n/es.i18n.json @@ -160,7 +160,9 @@ "rapid": "RÁPIDO", "rapid_subtitle": "Urgente mismo día", "create_order": "Crear Orden", - "create_order_subtitle": "Programar turnos" + "create_order_subtitle": "Programar turnos", + "hubs": "Hubs", + "hubs_subtitle": "Puntos marcaje" }, "reorder": { "title": "REORDENAR", diff --git a/apps/packages/core_localization/lib/src/l10n/strings.g.dart b/apps/packages/core_localization/lib/src/l10n/strings.g.dart index b377b0ea..1b162a64 100644 --- a/apps/packages/core_localization/lib/src/l10n/strings.g.dart +++ b/apps/packages/core_localization/lib/src/l10n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 332 (166 per locale) +/// Strings: 336 (168 per locale) /// -/// Built on 2026-01-22 at 00:48 UTC +/// Built on 2026-01-22 at 01:00 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/apps/packages/core_localization/lib/src/l10n/strings_en.g.dart b/apps/packages/core_localization/lib/src/l10n/strings_en.g.dart index e42d42a3..5d161669 100644 --- a/apps/packages/core_localization/lib/src/l10n/strings_en.g.dart +++ b/apps/packages/core_localization/lib/src/l10n/strings_en.g.dart @@ -496,6 +496,12 @@ class TranslationsClientHomeActionsEn { /// en: 'Schedule shifts' String get create_order_subtitle => 'Schedule shifts'; + + /// en: 'Hubs' + String get hubs => 'Hubs'; + + /// en: 'Clock-in points' + String get hubs_subtitle => 'Clock-in points'; } // Path: client_home.reorder @@ -999,6 +1005,8 @@ extension on Translations { 'client_home.actions.rapid_subtitle' => 'Urgent same-day', 'client_home.actions.create_order' => 'Create Order', 'client_home.actions.create_order_subtitle' => 'Schedule shifts', + 'client_home.actions.hubs' => 'Hubs', + 'client_home.actions.hubs_subtitle' => 'Clock-in points', 'client_home.reorder.title' => 'REORDER', 'client_home.reorder.reorder_button' => 'Reorder', 'client_home.reorder.per_hr' => ({required Object amount}) => '${amount}/hr', diff --git a/apps/packages/core_localization/lib/src/l10n/strings_es.g.dart b/apps/packages/core_localization/lib/src/l10n/strings_es.g.dart index 83958bd5..45d08748 100644 --- a/apps/packages/core_localization/lib/src/l10n/strings_es.g.dart +++ b/apps/packages/core_localization/lib/src/l10n/strings_es.g.dart @@ -323,6 +323,8 @@ class _TranslationsClientHomeActionsEs implements TranslationsClientHomeActionsE @override String get rapid_subtitle => 'Urgente mismo día'; @override String get create_order => 'Crear Orden'; @override String get create_order_subtitle => 'Programar turnos'; + @override String get hubs => 'Hubs'; + @override String get hubs_subtitle => 'Puntos marcaje'; } // Path: client_home.reorder @@ -661,6 +663,8 @@ extension on TranslationsEs { 'client_home.actions.rapid_subtitle' => 'Urgente mismo día', 'client_home.actions.create_order' => 'Crear Orden', 'client_home.actions.create_order_subtitle' => 'Programar turnos', + 'client_home.actions.hubs' => 'Hubs', + 'client_home.actions.hubs_subtitle' => 'Puntos marcaje', 'client_home.reorder.title' => 'REORDENAR', 'client_home.reorder.reorder_button' => 'Reordenar', 'client_home.reorder.per_hr' => ({required Object amount}) => '${amount}/hr', diff --git a/apps/packages/data_connect/lib/src/data_connect_module.dart b/apps/packages/data_connect/lib/src/data_connect_module.dart index 5651978f..553eac80 100644 --- a/apps/packages/data_connect/lib/src/data_connect_module.dart +++ b/apps/packages/data_connect/lib/src/data_connect_module.dart @@ -1,13 +1,15 @@ import 'package:flutter_modular/flutter_modular.dart'; import 'mocks/auth_repository_mock.dart'; +import 'mocks/business_repository_mock.dart'; import 'mocks/home_repository_mock.dart'; /// A module that provides Data Connect dependencies, including mocks. class DataConnectModule extends Module { @override void exportedBinds(Injector i) { - // Make the AuthRepositoryMock available to any module that imports this one. + // Make these mocks available to any module that imports this one. i.addLazySingleton(AuthRepositoryMock.new); i.addLazySingleton(HomeRepositoryMock.new); + i.addLazySingleton(BusinessRepositoryMock.new); } } diff --git a/apps/packages/features/client/home/lib/src/presentation/navigation/client_home_navigator.dart b/apps/packages/features/client/home/lib/src/presentation/navigation/client_home_navigator.dart index a973363e..c2eba106 100644 --- a/apps/packages/features/client/home/lib/src/presentation/navigation/client_home_navigator.dart +++ b/apps/packages/features/client/home/lib/src/presentation/navigation/client_home_navigator.dart @@ -12,4 +12,9 @@ extension ClientHomeNavigator on IModularNavigator { void pushSettings() { pushNamed('/client-settings/'); } + + /// Navigates to the hubs page. + void pushHubs() { + pushNamed('/client/hubs'); + } } diff --git a/apps/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart b/apps/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart index 83bbcf91..31f080da 100644 --- a/apps/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart +++ b/apps/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart @@ -324,6 +324,7 @@ class ClientHomePage extends StatelessWidget { return ActionsWidget( onRapidPressed: () {}, onCreateOrderPressed: () => _openOrderFormSheet(context, null), + onHubsPressed: () => Modular.to.pushHubs(), ); case 'reorder': return ReorderWidget( diff --git a/apps/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart b/apps/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart index 5a854195..167e5043 100644 --- a/apps/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart +++ b/apps/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart @@ -10,11 +10,15 @@ class ActionsWidget extends StatelessWidget { /// Callback when Create Order is pressed. final VoidCallback onCreateOrderPressed; + /// Callback when Hubs is pressed. + final VoidCallback onHubsPressed; + /// Creates an [ActionsWidget]. const ActionsWidget({ super.key, required this.onRapidPressed, required this.onCreateOrderPressed, + required this.onHubsPressed, }); @override @@ -53,6 +57,21 @@ class ActionsWidget extends StatelessWidget { onTap: onCreateOrderPressed, ), ), + const SizedBox(width: UiConstants.space2), + Expanded( + child: _ActionCard( + title: i18n.hubs, + subtitle: i18n.hubs_subtitle, + icon: UiIcons.nfc, + color: const Color(0xFFF0FDF4), + borderColor: const Color(0xFFBBF7D0), + iconBgColor: const Color(0xFFDCFCE7), + iconColor: const Color(0xFF16A34A), + textColor: const Color(0xFF064E3B), + subtitleColor: const Color(0xFF15803D), + onTap: onHubsPressed, + ), + ), ], ); } diff --git a/apps/packages/features/client/hubs/lib/src/presentation/navigation/client_hubs_navigator.dart b/apps/packages/features/client/hubs/lib/src/presentation/navigation/client_hubs_navigator.dart index cb534c0d..d5fe00e7 100644 --- a/apps/packages/features/client/hubs/lib/src/presentation/navigation/client_hubs_navigator.dart +++ b/apps/packages/features/client/hubs/lib/src/presentation/navigation/client_hubs_navigator.dart @@ -4,6 +4,6 @@ import 'package:flutter_modular/flutter_modular.dart'; extension ClientHubsNavigator on IModularNavigator { /// Navigates to the client hubs page. Future pushClientHubs() async { - await pushNamed('/client/hubs/'); + await pushNamed('/client/hubs'); } } diff --git a/apps/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart b/apps/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart index 3fa9ead4..6b38f064 100644 --- a/apps/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart +++ b/apps/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart @@ -196,6 +196,10 @@ class ClientHubsPage extends StatelessWidget { ).add(const ClientHubsAddDialogToggled(visible: true)), text: t.client_hubs.add_hub, leadingIcon: LucideIcons.plus, + style: ElevatedButton.styleFrom( + minimumSize: Size(0, 40), + maximumSize: Size.fromHeight(40), + ), ), ], ), diff --git a/apps/packages/features/client/settings/lib/src/presentation/navigation/client_settings_navigator.dart b/apps/packages/features/client/settings/lib/src/presentation/navigation/client_settings_navigator.dart index b5b454f5..6e0b2a1f 100644 --- a/apps/packages/features/client/settings/lib/src/presentation/navigation/client_settings_navigator.dart +++ b/apps/packages/features/client/settings/lib/src/presentation/navigation/client_settings_navigator.dart @@ -7,4 +7,9 @@ extension ClientSettingsNavigator on IModularNavigator { void pushClientSettings() { pushNamed('/client/settings/'); } + + /// Navigates to the hubs page. + void pushHubs() { + pushNamed('/client/hubs'); + } } diff --git a/apps/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_quick_links.dart b/apps/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_quick_links.dart index 5e33a33b..eed50780 100644 --- a/apps/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_quick_links.dart +++ b/apps/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_quick_links.dart @@ -1,6 +1,8 @@ import 'package:core_localization/core_localization.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_modular/flutter_modular.dart'; +import '../../navigation/client_settings_navigator.dart'; /// A widget that displays a list of quick links in a card. class SettingsQuickLinks extends StatelessWidget { @@ -34,7 +36,7 @@ class SettingsQuickLinks extends StatelessWidget { _QuickLinkItem( icon: UiIcons.nfc, title: labels.clock_in_hubs, - onTap: () {}, + onTap: () => Modular.to.pushHubs(), ), _QuickLinkItem( icon: UiIcons.building,