From 230942e776ea051f143bdc0535da6ba91479aefb Mon Sep 17 00:00:00 2001 From: Suriya Date: Thu, 19 Mar 2026 15:25:37 +0530 Subject: [PATCH] dev merge --- .../plugins/GeneratedPluginRegistrant.java | 5 + .../ios/Runner/GeneratedPluginRegistrant.m | 7 ++ .../endpoints/client_endpoints.dart | 5 + .../lib/src/entities/shifts/shift_detail.dart | 16 ++- .../client_create_order_repository_impl.dart | 5 +- .../domain/arguments/clock_in_arguments.dart | 11 +- .../domain/arguments/clock_out_arguments.dart | 10 +- .../bloc/clock_in/clock_in_bloc.dart | 2 + .../bloc/clock_in/clock_in_event.dart | 10 ++ .../widgets/tabs/find_shifts_tab.dart | 4 +- .../features/staff/shifts/pubspec.yaml | 1 + apps/mobile/pubspec.lock | 104 ++++++++++++++++-- 12 files changed, 156 insertions(+), 24 deletions(-) diff --git a/apps/mobile/apps/staff/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/apps/mobile/apps/staff/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java index faea8c4d..a550cc2f 100644 --- a/apps/mobile/apps/staff/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java +++ b/apps/mobile/apps/staff/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -45,6 +45,11 @@ public final class GeneratedPluginRegistrant { } catch (Exception e) { Log.e(TAG, "Error registering plugin geolocator_android, com.baseflow.geolocator.GeolocatorPlugin", e); } + try { + flutterEngine.getPlugins().add(new io.flutter.plugins.googlemaps.GoogleMapsPlugin()); + } catch (Exception e) { + Log.e(TAG, "Error registering plugin google_maps_flutter_android, io.flutter.plugins.googlemaps.GoogleMapsPlugin", e); + } try { flutterEngine.getPlugins().add(new io.flutter.plugins.imagepicker.ImagePickerPlugin()); } catch (Exception e) { diff --git a/apps/mobile/apps/staff/ios/Runner/GeneratedPluginRegistrant.m b/apps/mobile/apps/staff/ios/Runner/GeneratedPluginRegistrant.m index 1c6a698f..5212ec7d 100644 --- a/apps/mobile/apps/staff/ios/Runner/GeneratedPluginRegistrant.m +++ b/apps/mobile/apps/staff/ios/Runner/GeneratedPluginRegistrant.m @@ -36,6 +36,12 @@ @import geolocator_apple; #endif +#if __has_include() +#import +#else +@import google_maps_flutter_ios; +#endif + #if __has_include() #import #else @@ -86,6 +92,7 @@ [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]]; [FlutterLocalNotificationsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterLocalNotificationsPlugin"]]; [GeolocatorPlugin registerWithRegistrar:[registry registrarForPlugin:@"GeolocatorPlugin"]]; + [FGMGoogleMapsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FGMGoogleMapsPlugin"]]; [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; [FPPPackageInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPPackageInfoPlusPlugin"]]; [RecordIosPlugin registerWithRegistrar:[registry registrarForPlugin:@"RecordIosPlugin"]]; diff --git a/apps/mobile/packages/core/lib/src/services/api_service/endpoints/client_endpoints.dart b/apps/mobile/packages/core/lib/src/services/api_service/endpoints/client_endpoints.dart index aeb0f45f..b0f80c13 100644 --- a/apps/mobile/packages/core/lib/src/services/api_service/endpoints/client_endpoints.dart +++ b/apps/mobile/packages/core/lib/src/services/api_service/endpoints/client_endpoints.dart @@ -132,6 +132,11 @@ abstract final class ClientEndpoints { static const ApiEndpoint ordersOneTime = ApiEndpoint('/client/orders/one-time'); + /// Create rapid order. + static const ApiEndpoint ordersRapid = + ApiEndpoint('/client/orders/rapid'); + + /// Create recurring order. static const ApiEndpoint ordersRecurring = ApiEndpoint('/client/orders/recurring'); diff --git a/apps/mobile/packages/domain/lib/src/entities/shifts/shift_detail.dart b/apps/mobile/packages/domain/lib/src/entities/shifts/shift_detail.dart index c4082982..d664f919 100644 --- a/apps/mobile/packages/domain/lib/src/entities/shifts/shift_detail.dart +++ b/apps/mobile/packages/domain/lib/src/entities/shifts/shift_detail.dart @@ -37,9 +37,11 @@ class ShiftDetail extends Equatable { this.assignmentStatus, this.applicationStatus, this.clockInMode, - required this.allowClockInOverride, + this.allowClockInOverride = false, this.geofenceRadiusMeters, this.nfcTagId, + this.breakDurationMinutes, + this.isBreakPaid = false, }); /// Deserialises from the V2 API JSON response. @@ -75,6 +77,8 @@ class ShiftDetail extends Equatable { allowClockInOverride: json['allowClockInOverride'] as bool? ?? false, geofenceRadiusMeters: json['geofenceRadiusMeters'] as int?, nfcTagId: json['nfcTagId'] as String?, + breakDurationMinutes: json['breakDurationMinutes'] as int?, + isBreakPaid: json['isBreakPaid'] as bool? ?? false, ); } @@ -156,6 +160,12 @@ class ShiftDetail extends Equatable { /// NFC tag identifier for NFC-based clock-in. final String? nfcTagId; + /// Optional break duration in minutes. + final int? breakDurationMinutes; + + /// Whether the break is paid. + final bool isBreakPaid; + /// Duration of the shift in hours. double get durationHours { return endTime.difference(startTime).inMinutes / 60; @@ -193,6 +203,8 @@ class ShiftDetail extends Equatable { 'allowClockInOverride': allowClockInOverride, 'geofenceRadiusMeters': geofenceRadiusMeters, 'nfcTagId': nfcTagId, + 'breakDurationMinutes': breakDurationMinutes, + 'isBreakPaid': isBreakPaid, }; } @@ -224,5 +236,7 @@ class ShiftDetail extends Equatable { allowClockInOverride, geofenceRadiusMeters, nfcTagId, + breakDurationMinutes, + isBreakPaid, ]; } diff --git a/apps/mobile/packages/features/client/orders/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart b/apps/mobile/packages/features/client/orders/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart index 7739e41e..ecd6a58c 100644 --- a/apps/mobile/packages/features/client/orders/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart +++ b/apps/mobile/packages/features/client/orders/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart @@ -39,7 +39,10 @@ class ClientCreateOrderRepositoryImpl @override Future createRapidOrder(String description) async { - throw UnimplementedError('Rapid order creation is not connected yet.'); + await _api.post( + ClientEndpoints.ordersRapid, + data: {'description': description}, + ); } @override diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_in_arguments.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_in_arguments.dart index 6704f522..22d937dc 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_in_arguments.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_in_arguments.dart @@ -2,7 +2,6 @@ import 'package:krow_core/core.dart'; /// Represents the arguments required for the [ClockInUseCase]. class ClockInArguments extends UseCaseArgument { - /// Creates a [ClockInArguments] instance. const ClockInArguments({ required this.shiftId, @@ -18,6 +17,7 @@ class ClockInArguments extends UseCaseArgument { this.proofTimestamp, this.attestationProvider, this.attestationToken, + this.sourceType = 'GEO', }); /// The ID of the shift to clock in to. @@ -59,14 +59,16 @@ class ClockInArguments extends UseCaseArgument { /// Signed attestation token from the device integrity API. final String? attestationToken; + /// The source type of the clock-in (e.g. 'GEO', 'NFC', 'QR'). + final String sourceType; + /// Serializes the arguments to a JSON map for the V2 API request body. /// - /// Only includes non-null fields. The `sourceType` is inferred from - /// whether [nfcTagId] is present. + /// Only includes non-null fields. Map toJson() { return { 'shiftId': shiftId, - 'sourceType': nfcTagId != null ? 'NFC' : 'GEO', + 'sourceType': sourceType, if (notes != null && notes!.isNotEmpty) 'notes': notes, if (deviceId != null) 'deviceId': deviceId, if (latitude != null) 'latitude': latitude, @@ -101,5 +103,6 @@ class ClockInArguments extends UseCaseArgument { proofTimestamp, attestationProvider, attestationToken, + sourceType, ]; } diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_out_arguments.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_out_arguments.dart index f562cb6c..074987cd 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_out_arguments.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/domain/arguments/clock_out_arguments.dart @@ -18,6 +18,7 @@ class ClockOutArguments extends UseCaseArgument { this.proofTimestamp, this.attestationProvider, this.attestationToken, + this.sourceType = 'GEO', }); /// Optional notes provided by the user during clock-out. @@ -62,14 +63,16 @@ class ClockOutArguments extends UseCaseArgument { /// Signed attestation token from the device integrity API. final String? attestationToken; + /// The source type of the clock-out (e.g. 'GEO', 'NFC', 'QR'). + final String sourceType; + /// Serializes the arguments to a JSON map for the V2 API request body. /// - /// Only includes non-null fields. The `sourceType` is inferred from - /// whether [nfcTagId] is present. + /// Only includes non-null fields. Map toJson() { return { if (shiftId != null) 'shiftId': shiftId, - 'sourceType': nfcTagId != null ? 'NFC' : 'GEO', + 'sourceType': sourceType, if (notes != null && notes!.isNotEmpty) 'notes': notes, if (breakTimeMinutes != null) 'breakMinutes': breakTimeMinutes, if (deviceId != null) 'deviceId': deviceId, @@ -106,5 +109,6 @@ class ClockOutArguments extends UseCaseArgument { proofTimestamp, attestationProvider, attestationToken, + sourceType, ]; } diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_bloc.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_bloc.dart index 9c107915..dd572c5d 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_bloc.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_bloc.dart @@ -213,6 +213,7 @@ class ClockInBloc extends Bloc longitude: location?.longitude, accuracyMeters: location?.accuracy, capturedAt: location?.timestamp, + sourceType: event.sourceType, overrideReason: geofenceState.isGeofenceOverridden ? geofenceState.overrideNotes : null, @@ -291,6 +292,7 @@ class ClockInBloc extends Bloc longitude: location?.longitude, accuracyMeters: location?.accuracy, capturedAt: location?.timestamp, + sourceType: event.sourceType, overrideReason: currentGeofence.isGeofenceOverridden ? currentGeofence.overrideNotes : null, diff --git a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_event.dart b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_event.dart index 36652f26..699ffba7 100644 --- a/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_event.dart +++ b/apps/mobile/packages/features/staff/clock_in/lib/src/presentation/bloc/clock_in/clock_in_event.dart @@ -47,6 +47,7 @@ class CheckInRequested extends ClockInEvent { this.clockInGreetingBody = '', this.leftGeofenceTitle = '', this.leftGeofenceBody = '', + this.sourceType = 'GEO', }); /// The ID of the shift to clock into. @@ -67,6 +68,9 @@ class CheckInRequested extends ClockInEvent { /// Localized body for the left-geofence background notification. final String leftGeofenceBody; + /// The source type of the clock-in (e.g. 'GEO', 'NFC', 'QR'). + final String sourceType; + @override List get props => [ shiftId, @@ -75,6 +79,7 @@ class CheckInRequested extends ClockInEvent { clockInGreetingBody, leftGeofenceTitle, leftGeofenceBody, + sourceType, ]; } @@ -85,6 +90,7 @@ class CheckOutRequested extends ClockInEvent { this.breakTimeMinutes, this.clockOutTitle = '', this.clockOutBody = '', + this.sourceType = 'GEO', }); /// Optional notes provided by the user. @@ -99,12 +105,16 @@ class CheckOutRequested extends ClockInEvent { /// Localized body for the clock-out notification. final String clockOutBody; + /// The source type of the clock-out (e.g. 'GEO', 'NFC', 'QR'). + final String sourceType; + @override List get props => [ notes, breakTimeMinutes, clockOutTitle, clockOutBody, + sourceType, ]; } diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart index 40068e37..ff52bb95 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart @@ -2,6 +2,7 @@ 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 'package:geolocator/geolocator.dart'; import 'package:intl/intl.dart'; import 'package:krow_core/core.dart'; import 'package:krow_domain/krow_domain.dart'; @@ -147,8 +148,6 @@ class _FindShiftsTabState extends State { return DateFormat('EEE, MMM d').format(date); } - } - Widget _buildFilterTab(String id, String label) { final bool isSelected = _jobType == id; return GestureDetector( @@ -421,7 +420,6 @@ class _FindShiftsTabState extends State { ), ), ), - ), ], ), ), diff --git a/apps/mobile/packages/features/staff/shifts/pubspec.yaml b/apps/mobile/packages/features/staff/shifts/pubspec.yaml index a05c568e..f2d99023 100644 --- a/apps/mobile/packages/features/staff/shifts/pubspec.yaml +++ b/apps/mobile/packages/features/staff/shifts/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: url_launcher: ^6.3.1 bloc: ^8.1.4 meta: ^1.17.0 + google_maps_flutter: ^2.5.3 dev_dependencies: flutter_test: diff --git a/apps/mobile/pubspec.lock b/apps/mobile/pubspec.lock index 5c637621..846ef712 100644 --- a/apps/mobile/pubspec.lock +++ b/apps/mobile/pubspec.lock @@ -141,10 +141,10 @@ packages: dependency: transitive description: name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.0" charcode: dependency: transitive description: @@ -257,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" csv: dependency: transitive description: @@ -637,6 +645,54 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.2" + google_maps: + dependency: transitive + description: + name: google_maps + sha256: "5d410c32112d7c6eb7858d359275b2aa04778eed3e36c745aeae905fb2fa6468" + url: "https://pub.dev" + source: hosted + version: "8.2.0" + google_maps_flutter: + dependency: transitive + description: + name: google_maps_flutter + sha256: "0114a31e177f650f0972347d93122c42661a75b869561ff6a374cc42ff3af886" + url: "https://pub.dev" + source: hosted + version: "2.16.0" + google_maps_flutter_android: + dependency: transitive + description: + name: google_maps_flutter_android + sha256: "68a3907c90dc37caffbcfc1093541ef2c18d6ebb53296fdb9f04822d16269353" + url: "https://pub.dev" + source: hosted + version: "2.19.3" + google_maps_flutter_ios: + dependency: transitive + description: + name: google_maps_flutter_ios + sha256: c855600dce17e77e8af96edcf85cb68501675bb77a72f85009d08c17a8805ace + url: "https://pub.dev" + source: hosted + version: "2.18.0" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + sha256: ddbe34435dfb34e83fca295c6a8dcc53c3b51487e9eec3c737ce4ae605574347 + url: "https://pub.dev" + source: hosted + version: "2.15.0" + google_maps_flutter_web: + dependency: transitive + description: + name: google_maps_flutter_web + sha256: "6cefe4ef4cc61dc0dfba4c413dec4bd105cb6b9461bfbe1465ddd09f80af377d" + url: "https://pub.dev" + source: hosted + version: "0.6.2" google_places_flutter: dependency: transitive description: @@ -669,6 +725,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.5" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" http: dependency: transitive description: @@ -781,6 +845,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" json_annotation: dependency: transitive description: @@ -849,18 +921,18 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "0.11.1" melos: dependency: "direct dev" description: @@ -1197,6 +1269,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + sanitize_html: + dependency: transitive + description: + name: sanitize_html + sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" + url: "https://pub.dev" + source: hosted + version: "2.1.0" shared_preferences: dependency: transitive description: @@ -1412,26 +1492,26 @@ packages: dependency: transitive description: name: test - sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" + sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" url: "https://pub.dev" source: hosted - version: "1.29.0" + version: "1.26.3" test_api: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.7" test_core: dependency: transitive description: name: test_core - sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" + sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" url: "https://pub.dev" source: hosted - version: "0.6.15" + version: "0.6.12" timezone: dependency: transitive description: