diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart index ee5a22b2..371179f8 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart @@ -74,23 +74,32 @@ class ClientHomePage extends StatelessWidget { /// Builds the widget list in normal mode with visibility filters. Widget _buildNormalModeList(ClientHomeState state) { - return ListView( - padding: const EdgeInsets.fromLTRB( - UiConstants.space4, - 0, - UiConstants.space4, - 100, - ), - children: state.widgetOrder.map((String id) { - return Padding( - padding: const EdgeInsets.only(bottom: UiConstants.space4), - child: DashboardWidgetBuilder( - id: id, - state: state, - isEditMode: false, - ), + return ListView.separated( + padding: const EdgeInsets.only(bottom: 100), + separatorBuilder: (BuildContext context, int index) { + return const Divider(color: UiColors.border, height: 0.2); + }, + itemCount: state.widgetOrder.length, + itemBuilder: (BuildContext context, int index) { + final String id = state.widgetOrder[index]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (index != 0) const SizedBox(height: UiConstants.space8), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space4, + ), + child: DashboardWidgetBuilder( + id: id, + state: state, + isEditMode: false, + ), + ), + const SizedBox(height: UiConstants.space8), + ], ); - }).toList(), + }, ); } } diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart index 4298a37d..c5384950 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart +++ b/apps/mobile/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; + /// Optional subtitle for the section. + final String? subtitle; + /// Creates an [ActionsWidget]. const ActionsWidget({ super.key, required this.onRapidPressed, required this.onCreateOrderPressed, + this.subtitle, }); @override @@ -22,8 +26,11 @@ class ActionsWidget extends StatelessWidget { // Check if client_home exists in t final TranslationsClientHomeActionsEn i18n = t.client_home.actions; - return Row( + return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( + children: [ /// TODO: FEATURE_NOT_YET_IMPLEMENTED // Expanded( // child: _ActionCard( @@ -55,6 +62,8 @@ class ActionsWidget extends StatelessWidget { ), ), ], + ), + ], ); } } diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart index 03ac041d..473adc87 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart @@ -12,17 +12,22 @@ class CoverageWidget extends StatelessWidget { /// The percentage of coverage (0-100). final int coveragePercent; + /// 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) { return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -53,6 +58,12 @@ class CoverageWidget extends StatelessWidget { ), ], ), + if (subtitle != null) ...[ + Text( + subtitle!, + style: UiTypography.body2r.textSecondary, + ), + ], const SizedBox(height: UiConstants.space2), Row( children: [ diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart index 2fc51657..db0e237c 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/dashboard_widget_builder.dart @@ -56,11 +56,15 @@ class DashboardWidgetBuilder extends StatelessWidget { /// Builds the actual widget content based on the widget ID. Widget _buildWidgetContent(BuildContext context) { + // Only show subtitle in normal mode + final String? subtitle = !isEditMode ? _getWidgetSubtitle(id) : null; + switch (id) { case 'actions': return ActionsWidget( onRapidPressed: () => Modular.to.pushRapidOrder(), onCreateOrderPressed: () => Modular.to.pushCreateOrder(), + subtitle: subtitle, ); case 'reorder': return ReorderWidget( @@ -88,6 +92,7 @@ class DashboardWidgetBuilder extends StatelessWidget { }, ); }, + subtitle: subtitle, ); case 'spending': return SpendingWidget( @@ -95,6 +100,7 @@ class DashboardWidgetBuilder extends StatelessWidget { next7DaysSpending: state.dashboardData.next7DaysSpending, weeklyShifts: state.dashboardData.weeklyShifts, next7DaysScheduled: state.dashboardData.next7DaysScheduled, + subtitle: subtitle, ); case 'coverage': return CoverageWidget( @@ -106,10 +112,12 @@ class DashboardWidgetBuilder extends StatelessWidget { 100) .toInt() : 0, + subtitle: subtitle, ); case 'liveActivity': return LiveActivityWidget( onViewAllPressed: () => Modular.to.navigate('/client-main/coverage/'), + subtitle: subtitle, ); default: return const SizedBox.shrink(); @@ -133,4 +141,21 @@ class DashboardWidgetBuilder extends StatelessWidget { return ''; } } + + String _getWidgetSubtitle(String id) { + switch (id) { + case 'actions': + return 'Quick access to create and manage orders'; + case 'reorder': + return 'Easily reorder from your past activity'; + case 'spending': + return 'Track your spending and budget in real-time'; + case 'coverage': + return 'Overview of your current shift coverage'; + case 'liveActivity': + return 'Real-time updates on your active shifts'; + default: + return ''; + } + } } diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart index 7b442cf6..7c7c298a 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/live_activity_widget.dart @@ -10,8 +10,15 @@ 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({super.key, required this.onViewAllPressed}); + const LiveActivityWidget({ + super.key, + required this.onViewAllPressed, + this.subtitle + }); @override State createState() => _LiveActivityWidgetState(); @@ -100,6 +107,7 @@ class _LiveActivityWidgetState extends State { final TranslationsClientHomeEn i18n = t.client_home; return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -121,6 +129,13 @@ class _LiveActivityWidgetState extends State { ), ], ), + if (widget.subtitle != null) ...[ + const SizedBox(height: UiConstants.space1), + Text( + widget.subtitle!, + style: UiTypography.body2r.textSecondary, + ), + ], const SizedBox(height: UiConstants.space2), FutureBuilder<_LiveActivityData>( future: _liveActivityFuture, diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/reorder_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/reorder_widget.dart index b0147414..4adb0461 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/reorder_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/reorder_widget.dart @@ -11,11 +11,15 @@ class ReorderWidget extends StatelessWidget { /// Callback when a reorder button is pressed. final Function(Map shiftData) onReorderPressed; + /// Optional subtitle for the section. + final String? subtitle; + /// Creates a [ReorderWidget]. const ReorderWidget({ super.key, required this.orders, required this.onReorderPressed, + this.subtitle, }); @override @@ -33,6 +37,13 @@ class ReorderWidget extends StatelessWidget { letterSpacing: 0.5, ), ), + if (subtitle != null) ...[ + const SizedBox(height: UiConstants.space1), + Text( + subtitle!, + style: UiTypography.body2r.textSecondary, + ), + ], const SizedBox(height: UiConstants.space2), SizedBox( height: 140, diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart index 18ee5cd7..123876c1 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart @@ -16,6 +16,9 @@ class SpendingWidget extends StatelessWidget { /// The number of scheduled shifts for next 7 days. final int next7DaysScheduled; + /// Optional subtitle for the section. + final String? subtitle; + /// Creates a [SpendingWidget]. const SpendingWidget({ super.key, @@ -23,6 +26,7 @@ class SpendingWidget extends StatelessWidget { required this.next7DaysSpending, required this.weeklyShifts, required this.next7DaysScheduled, + this.subtitle, }); @override @@ -38,6 +42,13 @@ class SpendingWidget extends StatelessWidget { letterSpacing: 0.5, ), ), + if (subtitle != null) ...[ + const SizedBox(height: UiConstants.space1), + Text( + subtitle!, + style: UiTypography.body2r.textSecondary, + ), + ], const SizedBox(height: UiConstants.space2), Container( padding: const EdgeInsets.all(UiConstants.space3),