From 2c1c71ad01a74ecfa3c3dd2259b5254b2219db6c Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 13 Mar 2026 12:14:06 -0400 Subject: [PATCH] refactor: simplify widget structure and improve date selection logic in clock-in features --- .../widgets/clock_in_action_section.dart | 1 - .../presentation/widgets/date_selector.dart | 103 +++++++------- .../pages/shift_details_page.dart | 4 + .../shift_details/shift_details_header.dart | 130 +++++++----------- 4 files changed, 107 insertions(+), 131 deletions(-) diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/clock_in_action_section.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/clock_in_action_section.dart index b94f2da3..892f4502 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/clock_in_action_section.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/clock_in_action_section.dart @@ -4,7 +4,6 @@ import 'package:krow_domain/krow_domain.dart'; import '../bloc/clock_in_bloc.dart'; import '../bloc/clock_in_event.dart'; -import '../bloc/clock_in_state.dart'; import 'clock_in_helpers.dart'; import 'early_check_in_banner.dart'; import 'lunch_break_modal.dart'; diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/date_selector.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/date_selector.dart index 2d849477..c91be1a4 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/date_selector.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/date_selector.dart @@ -16,7 +16,7 @@ class DateSelector extends StatelessWidget { @override Widget build(BuildContext context) { final DateTime today = DateTime.now(); - final List dates = List.generate(7, (int index) { + final List dates = List.generate(7, (int index) { return today.add(Duration(days: index - 3)); }); @@ -31,7 +31,7 @@ class DateSelector extends StatelessWidget { return Expanded( child: GestureDetector( - onTap: () => onSelect(date), + onTap: isToday ? () => onSelect(date) : null, child: AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.symmetric( @@ -40,58 +40,55 @@ class DateSelector extends StatelessWidget { decoration: BoxDecoration( color: isSelected ? UiColors.primary : UiColors.white, borderRadius: UiConstants.radiusLg, - boxShadow: isSelected - ? [ - BoxShadow( - color: UiColors.primary.withValues(alpha: 0.3), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ] - : [], ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - DateFormat('d').format(date), - style: UiTypography.title1m.copyWith( - fontWeight: FontWeight.bold, - color: - isSelected ? UiColors.white : UiColors.foreground, - ), - ), - const SizedBox(height: 2), - Text( - DateFormat('E').format(date), - style: UiTypography.footnote2r.copyWith( - color: isSelected - ? UiColors.white.withValues(alpha: 0.8) - : UiColors.textInactive, - ), - ), - const SizedBox(height: UiConstants.space1), - if (hasShift) - Container( - width: 6, - height: 6, - decoration: BoxDecoration( - color: isSelected ? UiColors.white : UiColors.primary, - shape: BoxShape.circle, + child: Opacity( + opacity: isToday ? 1.0 : 0.4, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + DateFormat('d').format(date), + style: UiTypography.title1m.copyWith( + fontWeight: FontWeight.bold, + color: isSelected + ? UiColors.white + : UiColors.foreground, ), - ) - else if (isToday && !isSelected) - Container( - width: 6, - height: 6, - decoration: const BoxDecoration( - color: UiColors.border, - shape: BoxShape.circle, + ), + const SizedBox(height: 2), + Text( + DateFormat('E').format(date), + style: UiTypography.footnote2r.copyWith( + color: isSelected + ? UiColors.white.withValues(alpha: 0.8) + : UiColors.textInactive, ), - ) - else - const SizedBox(height: 6), - ], + ), + const SizedBox(height: UiConstants.space1), + if (hasShift) + Container( + width: 6, + height: 6, + decoration: BoxDecoration( + color: isSelected + ? UiColors.white + : UiColors.primary, + shape: BoxShape.circle, + ), + ) + else if (isToday && !isSelected) + Container( + width: 6, + height: 6, + decoration: const BoxDecoration( + color: UiColors.border, + shape: BoxShape.circle, + ), + ) + else + const SizedBox(height: UiConstants.space3), + ], + ), ), ), ), @@ -100,11 +97,13 @@ class DateSelector extends StatelessWidget { ), ); } - + + /// Helper to check if two dates are on the same calendar day (ignoring time). bool _isSameDay(DateTime a, DateTime b) { return a.year == b.year && a.month == b.month && a.day == b.day; } + /// Formats a [DateTime] as an ISO date string (yyyy-MM-dd) for comparison with shift dates. String _formatDateIso(DateTime date) { return DateFormat('yyyy-MM-dd').format(date); } diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart index 0a56ae04..15b28f85 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart @@ -155,7 +155,9 @@ class _ShiftDetailsPageState extends State { ), ), ShiftDetailsHeader(shift: displayShift), + const Divider(height: 1, thickness: 0.5), + ShiftStatsRow( estimatedTotal: estimatedTotal, hourlyRate: displayShift.hourlyRate, @@ -164,7 +166,9 @@ class _ShiftDetailsPageState extends State { hourlyRateLabel: i18n.hourly_rate, hoursLabel: i18n.hours, ), + const Divider(height: 1, thickness: 0.5), + ShiftDateTimeSection( date: displayShift.date, endDate: displayShift.endDate, diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_details/shift_details_header.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_details/shift_details_header.dart index 4d6458f7..ea594220 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_details/shift_details_header.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_details/shift_details_header.dart @@ -8,93 +8,67 @@ class ShiftDetailsHeader extends StatelessWidget { final Shift shift; /// Creates a [ShiftDetailsHeader]. - const ShiftDetailsHeader({ - super.key, - required this.shift, - }); + const ShiftDetailsHeader({super.key, required this.shift}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(UiConstants.space5), - child: IntrinsicHeight( - child: Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - spacing: UiConstants.space4, - children: [ - Container( - width: 114, - decoration: BoxDecoration( - color: UiColors.primary.withAlpha(20), - borderRadius: BorderRadius.circular( - UiConstants.radiusBase, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: UiConstants.space4, + children: [ + // Icon + role name + client name + Row( + crossAxisAlignment: CrossAxisAlignment.center, + spacing: UiConstants.space4, + children: [ + Container( + width: 68, + height: 68, + decoration: BoxDecoration( + color: UiColors.primary.withAlpha(20), + borderRadius: UiConstants.radiusLg, + border: Border.all(color: UiColors.primary, width: 0.5), ), - border: Border.all(color: UiColors.primary), - ), - child: const Center( - child: Icon( - UiIcons.briefcase, - color: UiColors.primary, - size: 24, + child: const Center( + child: Icon( + UiIcons.briefcase, + color: UiColors.primary, + size: 20, + ), ), ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - spacing: UiConstants.space3, - children: [ - Text( - shift.title, - style: UiTypography.headline1b.textPrimary, - ), - Column( - spacing: UiConstants.space1, - children: [ - // Client name - Row( - spacing: UiConstants.space1, - children: [ - const Icon( - UiIcons.building, - size: 16, - color: UiColors.textSecondary, - ), - Expanded( - child: Text( - shift.clientName, - style: UiTypography.body1m.textSecondary, - ), - ), - ], - ), - - // Location address (if available) - Row( - spacing: UiConstants.space1, - children: [ - const Icon( - UiIcons.mapPin, - size: 16, - color: UiColors.textSecondary, - ), - Expanded( - child: Text( - shift.locationAddress, - style: UiTypography.body2r.textSecondary, - ), - ), - ], - ), - ], - ), - - ], + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(shift.title, style: UiTypography.headline1b.textPrimary), + Text(shift.clientName, style: UiTypography.body1m.textSecondary), + ], + ), ), - ), - ], - ), + ], + ), + + // Location address + Row( + spacing: UiConstants.space1, + children: [ + const Icon( + UiIcons.mapPin, + size: 16, + color: UiColors.textSecondary, + ), + Expanded( + child: Text( + shift.locationAddress, + style: UiTypography.body2r.textSecondary, + ), + ), + ], + ), + ], ), ); }