feat: Update geofence handling to allow checkout when checked in and show verified banner for overridden geofence

This commit is contained in:
Achintha Isuru
2026-03-13 20:43:51 -04:00
parent ea078eaa02
commit 1bbd306ca0
3 changed files with 19 additions and 7 deletions

View File

@@ -119,9 +119,10 @@ class ClockInActionSection extends StatelessWidget {
final bool hasCoordinates = selectedShift?.latitude != null &&
selectedShift?.longitude != null;
// Disable swipe when the shift has coordinates and the user is
// not verified, not timed out, and has not overridden the geofence.
final bool isGeofenceBlocking = hasCoordinates &&
// Geofence only gates clock-in, never clock-out. When already
// checked in the swipe must always be enabled for checkout.
final bool isGeofenceBlocking = !isCheckedIn &&
hasCoordinates &&
!geofenceState.isLocationVerified &&
!geofenceState.isLocationTimedOut &&
!geofenceState.isGeofenceOverridden;
@@ -135,7 +136,7 @@ class ClockInActionSection extends StatelessWidget {
SwipeToCheckIn(
isCheckedIn: isCheckedIn,
mode: checkInMode,
isDisabled: isCheckedIn || isGeofenceBlocking,
isDisabled: isGeofenceBlocking,
isLoading: isActionInProgress,
onCheckIn: () => _handleCheckIn(context),
onCheckOut: () => _handleCheckOut(context),

View File

@@ -20,8 +20,12 @@ class GeofenceOverrideModal extends StatefulWidget {
/// Shows the override modal as a bottom sheet.
///
/// Requires [ClockInBloc] to be available in [context].
/// Requires [GeofenceBloc] to be available in [context].
static void show(BuildContext context) {
// Capture the bloc before opening the sheet so we don't access a
// deactivated widget's ancestor inside the builder.
final GeofenceBloc bloc = ReadContext(context).read<GeofenceBloc>();
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
@@ -31,7 +35,7 @@ class GeofenceOverrideModal extends StatefulWidget {
),
),
builder: (_) => BlocProvider<GeofenceBloc>.value(
value: ReadContext(context).read<GeofenceBloc>(),
value: bloc,
child: const GeofenceOverrideModal(),
),
);
@@ -111,6 +115,7 @@ class _GeofenceOverrideModalState extends State<GeofenceOverrideModal> {
GeofenceOverrideApproved(notes: justification),
);
Modular.to.popSafe();
Navigator.of(context).pop();
//Modular.to.popSafe();
}
}

View File

@@ -35,6 +35,12 @@ class GeofenceStatusBanner extends StatelessWidget {
/// Determines which banner variant to display based on the current state.
Widget _buildBannerForState(GeofenceState state) {
// If the worker overrode the geofence check, show the verified banner
// instead of any failure state — the justification has been recorded.
if (state.isGeofenceOverridden) {
return const VerifiedBanner();
}
// 1. Location services disabled.
if (state.permissionStatus == LocationPermissionStatus.serviceDisabled ||
(state.isLocationTimedOut && !state.isLocationServiceEnabled)) {