diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/data/repositories_impl/clock_in_repository_impl.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/data/repositories_impl/clock_in_repository_impl.dart index 51b1b5ac..5bf40f00 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/data/repositories_impl/clock_in_repository_impl.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/data/repositories_impl/clock_in_repository_impl.dart @@ -129,6 +129,8 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface { createdDate: _toDateTime(fullShift.createdAt)?.toIso8601String() ?? '', status: fullShift.status?.stringValue, description: fullShift.description, + latitude: fullShift.latitude, + longitude: fullShift.longitude, ); } @@ -186,10 +188,4 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface { return getAttendanceStatus(); } - - @override - Future>> getActivityLog() async { - // Placeholder as this wasn't main focus and returns raw maps - return >[]; - } } diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/repositories/clock_in_repository_interface.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/repositories/clock_in_repository_interface.dart index c934a533..f37f1814 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/repositories/clock_in_repository_interface.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/repositories/clock_in_repository_interface.dart @@ -18,7 +18,4 @@ abstract class ClockInRepositoryInterface { /// Checks the user out for the currently active shift. /// Optionally accepts [breakTimeMinutes] if tracked. Future clockOut({String? notes, int? breakTimeMinutes}); - - /// Retrieves a list of recent clock-in/out activities. - Future>> getActivityLog(); } diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/usecases/get_activity_log_usecase.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/usecases/get_activity_log_usecase.dart deleted file mode 100644 index 04b908dc..00000000 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/usecases/get_activity_log_usecase.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:krow_core/core.dart'; -import '../repositories/clock_in_repository_interface.dart'; - -/// Use case for retrieving the activity log. -class GetActivityLogUseCase implements NoInputUseCase>> { - final ClockInRepositoryInterface _repository; - - GetActivityLogUseCase(this._repository); - - @override - Future>> call() { - return _repository.getActivityLog(); - } -} diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_bloc.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_bloc.dart index 763d2943..88a22e0a 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_bloc.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_bloc.dart @@ -4,7 +4,6 @@ import '../../domain/usecases/get_todays_shift_usecase.dart'; import '../../domain/usecases/get_attendance_status_usecase.dart'; import '../../domain/usecases/clock_in_usecase.dart'; import '../../domain/usecases/clock_out_usecase.dart'; -import '../../domain/usecases/get_activity_log_usecase.dart'; import '../../domain/arguments/clock_in_arguments.dart'; import '../../domain/arguments/clock_out_arguments.dart'; import 'clock_in_event.dart'; @@ -15,11 +14,8 @@ class ClockInBloc extends Bloc { final GetAttendanceStatusUseCase _getAttendanceStatus; final ClockInUseCase _clockIn; final ClockOutUseCase _clockOut; - final GetActivityLogUseCase _getActivityLog; // Mock Venue Location (e.g., Grand Hotel, NYC) - static const double venueLat = 40.7128; - static const double venueLng = -74.0060; static const double allowedRadiusMeters = 500; ClockInBloc({ @@ -27,12 +23,10 @@ class ClockInBloc extends Bloc { required GetAttendanceStatusUseCase getAttendanceStatus, required ClockInUseCase clockIn, required ClockOutUseCase clockOut, - required GetActivityLogUseCase getActivityLog, }) : _getTodaysShift = getTodaysShift, _getAttendanceStatus = getAttendanceStatus, _clockIn = clockIn, _clockOut = clockOut, - _getActivityLog = getActivityLog, super(ClockInState(selectedDate: DateTime.now())) { on(_onLoaded); on(_onDateSelected); @@ -54,7 +48,6 @@ class ClockInBloc extends Bloc { try { final shift = await _getTodaysShift(); final status = await _getAttendanceStatus(); - final activity = await _getActivityLog(); // Check permissions silently on load? Maybe better to wait for user interaction or specific event // However, if shift exists, we might want to check permission state @@ -63,7 +56,6 @@ class ClockInBloc extends Bloc { status: ClockInStatus.success, todayShift: shift, attendance: status, - activityLog: activity, )); if (shift != null && !status.isCheckedIn) { @@ -103,13 +95,23 @@ class ClockInBloc extends Bloc { void _startLocationUpdates() async { try { final position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high); - final distance = Geolocator.distanceBetween( - position.latitude, - position.longitude, - venueLat, - venueLng, - ); - final isVerified = distance <= allowedRadiusMeters; + + double distance = 0; + bool isVerified = false; // Require location match by default if shift has location + + if (state.todayShift != null && state.todayShift!.latitude != null && state.todayShift!.longitude != null) { + distance = Geolocator.distanceBetween( + position.latitude, + position.longitude, + state.todayShift!.latitude!, + state.todayShift!.longitude!, + ); + isVerified = distance <= allowedRadiusMeters; + } else { + // If no shift location, assume verified or don't restrict? + // For strict clock-in, maybe false? but let's default to verified to avoid blocking if data missing + isVerified = true; + } if (!isClosed) { add(LocationUpdated(position: position, distance: distance, isVerified: isVerified)); diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_state.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_state.dart index eadc30a8..11fe9813 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_state.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in_state.dart @@ -9,7 +9,6 @@ class ClockInState extends Equatable { final ClockInStatus status; final Shift? todayShift; final AttendanceStatus attendance; - final List> activityLog; final DateTime selectedDate; final String checkInMode; final String? errorMessage; @@ -25,7 +24,6 @@ class ClockInState extends Equatable { this.status = ClockInStatus.initial, this.todayShift, this.attendance = const AttendanceStatus(), - this.activityLog = const [], required this.selectedDate, this.checkInMode = 'swipe', this.errorMessage, @@ -41,7 +39,6 @@ class ClockInState extends Equatable { ClockInStatus? status, Shift? todayShift, AttendanceStatus? attendance, - List>? activityLog, DateTime? selectedDate, String? checkInMode, String? errorMessage, @@ -56,7 +53,6 @@ class ClockInState extends Equatable { status: status ?? this.status, todayShift: todayShift ?? this.todayShift, attendance: attendance ?? this.attendance, - activityLog: activityLog ?? this.activityLog, selectedDate: selectedDate ?? this.selectedDate, checkInMode: checkInMode ?? this.checkInMode, errorMessage: errorMessage, @@ -74,7 +70,6 @@ class ClockInState extends Equatable { status, todayShift, attendance, - activityLog, selectedDate, checkInMode, errorMessage, diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/pages/clock_in_page.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/pages/clock_in_page.dart index 33459844..ac848b2e 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/pages/clock_in_page.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/pages/clock_in_page.dart @@ -3,13 +3,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:intl/intl.dart'; +import 'package:krow_domain/krow_domain.dart'; import 'package:lucide_icons/lucide_icons.dart'; import '../bloc/clock_in_bloc.dart'; import '../bloc/clock_in_event.dart'; import '../bloc/clock_in_state.dart'; import '../theme/app_colors.dart'; -import '../widgets/attendance_card.dart'; import '../widgets/commute_tracker.dart'; import '../widgets/date_selector.dart'; import '../widgets/lunch_break_modal.dart'; @@ -135,13 +135,6 @@ class _ClockInPageState extends State { border: Border.all( color: const Color(0xFFE2E8F0), ), // slate-200 - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -417,78 +410,7 @@ class _ClockInPageState extends State { const SizedBox(height: 16), - // Recent Activity List - if (state.activityLog.isNotEmpty) - ...state.activityLog.map( - (activity) => Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFF8F9FA), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFF1F5F9), - ), // slate-100 - ), - child: Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity( - 0.1, - ), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.mapPin, - color: AppColors.krowBlue, - size: 20, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - DateFormat('MMM d').format( - activity['date'] as DateTime, - ), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color( - 0xFF0F172A, - ), // slate-900 - ), - ), - Text( - "${activity['start']} - ${activity['end']}", - style: const TextStyle( - fontSize: 12, - color: Color( - 0xFF64748B, - ), // slate-500 - ), - ), - ], - ), - ), - Text( - activity['hours'] as String, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowBlue, - ), - ), - ], - ), - ), - ), + // Recent Activity List (Temporarily removed) const SizedBox(height: 16), ], ), @@ -552,87 +474,6 @@ class _ClockInPageState extends State { ); } - Widget _buildHeader() { - return Padding( - padding: const EdgeInsets.fromLTRB(20, 24, 20, 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: AppColors.krowBlue.withOpacity(0.2), - width: 2, - ), - ), - child: CircleAvatar( - backgroundColor: AppColors.krowBlue.withOpacity(0.1), - child: const Text( - 'K', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Good Morning', - style: TextStyle(color: AppColors.krowMuted, fontSize: 12), - ), - Text( - 'Krower', - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - Text( - 'Warehouse Assistant', - style: TextStyle(color: AppColors.krowMuted, fontSize: 12), - ), - ], - ), - ], - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular( - 20, - ), // Rounded full for this page per design - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: const Icon( - LucideIcons.bell, - color: AppColors.krowMuted, - size: 20, - ), - ), - ], - ), - ); - } - Future _showNFCDialog(BuildContext context) async { bool scanned = false; @@ -739,23 +580,32 @@ class _ClockInPageState extends State { // --- Helper Methods --- String _formatTime(String timeStr) { - // Expecting HH:mm or HH:mm:ss + if (timeStr.isEmpty) return ''; try { - if (timeStr.isEmpty) return ''; - final parts = timeStr.split(':'); - final dt = DateTime(2022, 1, 1, int.parse(parts[0]), int.parse(parts[1])); + // Try parsing as ISO string first (which contains date) + final dt = DateTime.parse(timeStr); return DateFormat('h:mm a').format(dt); - } catch (e) { - return timeStr; + } catch (_) { + // Fallback for strict "HH:mm" or "HH:mm:ss" strings + try { + final parts = timeStr.split(':'); + if (parts.length >= 2) { + final dt = DateTime(2022, 1, 1, int.parse(parts[0]), int.parse(parts[1])); + return DateFormat('h:mm a').format(dt); + } + return timeStr; + } catch (e) { + return timeStr; + } } } - bool _isCheckInAllowed(dynamic shift) { + bool _isCheckInAllowed(Shift shift) { if (shift == null) return false; try { // Parse shift date (e.g. 2024-01-31T09:00:00) // The Shift entity has 'date' which is the start DateTime string - final shiftStart = DateTime.parse(shift.date); + final shiftStart = DateTime.parse(shift.startTime); final windowStart = shiftStart.subtract(const Duration(minutes: 15)); return DateTime.now().isAfter(windowStart); } catch (e) { @@ -764,10 +614,10 @@ class _ClockInPageState extends State { } } - String _getCheckInAvailabilityTime(dynamic shift) { + String _getCheckInAvailabilityTime(Shift shift) { if (shift == null) return ''; try { - final shiftStart = DateTime.parse(shift.date); + final shiftStart = DateTime.parse(shift.endTime); final windowStart = shiftStart.subtract(const Duration(minutes: 15)); return DateFormat('h:mm a').format(windowStart); } catch (e) { diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/commute_tracker.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/commute_tracker.dart index 9d0b4131..ff3b71a7 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/commute_tracker.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/widgets/commute_tracker.dart @@ -66,9 +66,14 @@ class _CommuteTrackerState extends State { // For demo purposes, check if we're within 24 hours of shift final now = DateTime.now(); - final shiftStart = DateTime.parse( - '${widget.shift!.date} ${widget.shift!.startTime}', - ); + DateTime shiftStart; + try { + shiftStart = DateTime.parse(widget.shift!.startTime); + } catch (_) { + shiftStart = DateTime.parse( + '${widget.shift!.date} ${widget.shift!.startTime}', + ); + } final hoursUntilShift = shiftStart.difference(now).inHours; final inCommuteWindow = hoursUntilShift <= 24 && hoursUntilShift >= 0; diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/staff_clock_in_module.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/staff_clock_in_module.dart index 16c0a809..3dc99996 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/staff_clock_in_module.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/staff_clock_in_module.dart @@ -6,7 +6,6 @@ import 'data/repositories_impl/clock_in_repository_impl.dart'; import 'domain/repositories/clock_in_repository_interface.dart'; import 'domain/usecases/clock_in_usecase.dart'; import 'domain/usecases/clock_out_usecase.dart'; -import 'domain/usecases/get_activity_log_usecase.dart'; import 'domain/usecases/get_attendance_status_usecase.dart'; import 'domain/usecases/get_todays_shift_usecase.dart'; import 'presentation/bloc/clock_in_bloc.dart'; @@ -28,7 +27,6 @@ class StaffClockInModule extends Module { i.add(GetAttendanceStatusUseCase.new); i.add(ClockInUseCase.new); i.add(ClockOutUseCase.new); - i.add(GetActivityLogUseCase.new); // BLoC i.add(ClockInBloc.new); diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/navigation/shifts_navigator.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/navigation/shifts_navigator.dart index 007b4e00..046fc08e 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/navigation/shifts_navigator.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/navigation/shifts_navigator.dart @@ -2,7 +2,11 @@ import 'package:flutter_modular/flutter_modular.dart'; import 'package:krow_domain/krow_domain.dart'; extension ShiftsNavigator on IModularNavigator { + void navigateToShiftsHome() { + navigate('/worker-main/shifts/'); + } + void pushShiftDetails(Shift shift) { - pushNamed('/worker-main/shift-details/${shift.id}', arguments: shift); + navigate('/worker-main/shift-details/${shift.id}', arguments: shift); } }