Merge remote-tracking branch 'origin/fix_staff_app_bugs' into 312-feature-integrate-google-maps-places-autocomplete-for-hub-address-validation
This commit is contained in:
@@ -1,21 +1,143 @@
|
|||||||
PODS:
|
PODS:
|
||||||
|
- AppCheckCore (11.2.0):
|
||||||
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||||
|
- PromisesObjC (~> 2.4)
|
||||||
|
- Firebase/AppCheck (12.8.0):
|
||||||
|
- Firebase/CoreOnly
|
||||||
|
- FirebaseAppCheck (~> 12.8.0)
|
||||||
|
- Firebase/Auth (12.8.0):
|
||||||
|
- Firebase/CoreOnly
|
||||||
|
- FirebaseAuth (~> 12.8.0)
|
||||||
|
- Firebase/CoreOnly (12.8.0):
|
||||||
|
- FirebaseCore (~> 12.8.0)
|
||||||
|
- firebase_app_check (0.4.1-4):
|
||||||
|
- Firebase/AppCheck (~> 12.8.0)
|
||||||
|
- Firebase/CoreOnly (~> 12.8.0)
|
||||||
|
- firebase_core
|
||||||
|
- FlutterMacOS
|
||||||
|
- firebase_auth (6.1.4):
|
||||||
|
- Firebase/Auth (~> 12.8.0)
|
||||||
|
- Firebase/CoreOnly (~> 12.8.0)
|
||||||
|
- firebase_core
|
||||||
|
- FlutterMacOS
|
||||||
|
- firebase_core (4.4.0):
|
||||||
|
- Firebase/CoreOnly (~> 12.8.0)
|
||||||
|
- FlutterMacOS
|
||||||
|
- FirebaseAppCheck (12.8.0):
|
||||||
|
- AppCheckCore (~> 11.0)
|
||||||
|
- FirebaseAppCheckInterop (~> 12.8.0)
|
||||||
|
- FirebaseCore (~> 12.8.0)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
|
- FirebaseAppCheckInterop (12.8.0)
|
||||||
|
- FirebaseAuth (12.8.0):
|
||||||
|
- FirebaseAppCheckInterop (~> 12.8.0)
|
||||||
|
- FirebaseAuthInterop (~> 12.8.0)
|
||||||
|
- FirebaseCore (~> 12.8.0)
|
||||||
|
- FirebaseCoreExtension (~> 12.8.0)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GTMSessionFetcher/Core (< 6.0, >= 3.4)
|
||||||
|
- RecaptchaInterop (~> 101.0)
|
||||||
|
- FirebaseAuthInterop (12.8.0)
|
||||||
|
- FirebaseCore (12.8.0):
|
||||||
|
- FirebaseCoreInternal (~> 12.8.0)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GoogleUtilities/Logger (~> 8.1)
|
||||||
|
- FirebaseCoreExtension (12.8.0):
|
||||||
|
- FirebaseCore (~> 12.8.0)
|
||||||
|
- FirebaseCoreInternal (12.8.0):
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
|
- geolocator_apple (1.2.0):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
||||||
|
- GoogleUtilities/Environment
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Network
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Environment (8.1.0):
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Logger (8.1.0):
|
||||||
|
- GoogleUtilities/Environment
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Network (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- "GoogleUtilities/NSData+zlib"
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Reachability
|
||||||
|
- "GoogleUtilities/NSData+zlib (8.1.0)":
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Privacy (8.1.0)
|
||||||
|
- GoogleUtilities/Reachability (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/UserDefaults (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GTMSessionFetcher/Core (5.0.0)
|
||||||
|
- PromisesObjC (2.4.0)
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
|
- firebase_app_check (from `Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos`)
|
||||||
|
- firebase_auth (from `Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos`)
|
||||||
|
- firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
|
- geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
|
|
||||||
|
SPEC REPOS:
|
||||||
|
trunk:
|
||||||
|
- AppCheckCore
|
||||||
|
- Firebase
|
||||||
|
- FirebaseAppCheck
|
||||||
|
- FirebaseAppCheckInterop
|
||||||
|
- FirebaseAuth
|
||||||
|
- FirebaseAuthInterop
|
||||||
|
- FirebaseCore
|
||||||
|
- FirebaseCoreExtension
|
||||||
|
- FirebaseCoreInternal
|
||||||
|
- GoogleUtilities
|
||||||
|
- GTMSessionFetcher
|
||||||
|
- PromisesObjC
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
firebase_app_check:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos
|
||||||
|
firebase_auth:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos
|
||||||
|
firebase_core:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos
|
||||||
FlutterMacOS:
|
FlutterMacOS:
|
||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
|
geolocator_apple:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
|
||||||
|
Firebase: 9a58fdbc9d8655ed7b79a19cf9690bb007d3d46d
|
||||||
|
firebase_app_check: daf97f2d7044e28b68d23bc90e16751acee09732
|
||||||
|
firebase_auth: 2c2438e41f061c03bd67dcb045dfd7bc843b5f52
|
||||||
|
firebase_core: b1697fb64ff2b9ca16baaa821205f8b0c058e5d2
|
||||||
|
FirebaseAppCheck: 11da425929a45c677d537adfff3520ccd57c1690
|
||||||
|
FirebaseAppCheckInterop: ba3dc604a89815379e61ec2365101608d365cf7d
|
||||||
|
FirebaseAuth: 4c289b1a43f5955283244a55cf6bd616de344be5
|
||||||
|
FirebaseAuthInterop: 95363fe96493cb4f106656666a0768b420cba090
|
||||||
|
FirebaseCore: 0dbad74bda10b8fb9ca34ad8f375fb9dd3ebef7c
|
||||||
|
FirebaseCoreExtension: 6605938d51f765d8b18bfcafd2085276a252bee2
|
||||||
|
FirebaseCoreInternal: fe5fa466aeb314787093a7dce9f0beeaad5a2a21
|
||||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
|
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
|
||||||
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
|
GTMSessionFetcher: 02d6e866e90bc236f48a703a041dfe43e6221a29
|
||||||
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
|
|
||||||
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Basic Usage
|
# Basic Usage
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
ExampleConnector.instance.createApplication(createApplicationVariables).execute();
|
ExampleConnector.instance.CreateStaff(createStaffVariables).execute();
|
||||||
ExampleConnector.instance.updateApplicationStatus(updateApplicationStatusVariables).execute();
|
ExampleConnector.instance.UpdateStaff(updateStaffVariables).execute();
|
||||||
ExampleConnector.instance.deleteApplication(deleteApplicationVariables).execute();
|
ExampleConnector.instance.DeleteStaff(deleteStaffVariables).execute();
|
||||||
ExampleConnector.instance.createStaffRole(createStaffRoleVariables).execute();
|
ExampleConnector.instance.listStaffAvailabilities(listStaffAvailabilitiesVariables).execute();
|
||||||
ExampleConnector.instance.deleteStaffRole(deleteStaffRoleVariables).execute();
|
ExampleConnector.instance.listStaffAvailabilitiesByStaffId(listStaffAvailabilitiesByStaffIdVariables).execute();
|
||||||
ExampleConnector.instance.CreateUser(createUserVariables).execute();
|
ExampleConnector.instance.getStaffAvailabilityByKey(getStaffAvailabilityByKeyVariables).execute();
|
||||||
ExampleConnector.instance.UpdateUser(updateUserVariables).execute();
|
ExampleConnector.instance.listStaffAvailabilitiesByDay(listStaffAvailabilitiesByDayVariables).execute();
|
||||||
ExampleConnector.instance.DeleteUser(deleteUserVariables).execute();
|
ExampleConnector.instance.createStaffAvailabilityStats(createStaffAvailabilityStatsVariables).execute();
|
||||||
ExampleConnector.instance.createUserConversation(createUserConversationVariables).execute();
|
ExampleConnector.instance.updateStaffAvailabilityStats(updateStaffAvailabilityStatsVariables).execute();
|
||||||
ExampleConnector.instance.updateUserConversation(updateUserConversationVariables).execute();
|
ExampleConnector.instance.deleteStaffAvailabilityStats(deleteStaffAvailabilityStatsVariables).execute();
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -23,8 +23,8 @@ Optional fields can be discovered based on classes that have `Optional` object t
|
|||||||
This is an example of a mutation with an optional field:
|
This is an example of a mutation with an optional field:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
await ExampleConnector.instance.filterUsers({ ... })
|
await ExampleConnector.instance.searchInvoiceTemplatesByOwnerAndName({ ... })
|
||||||
.id(...)
|
.offset(...)
|
||||||
.execute();
|
.execute();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -144,6 +144,8 @@ class GetApplicationsByStaffIdApplicationsShift {
|
|||||||
final EnumValue<ShiftStatus>? status;
|
final EnumValue<ShiftStatus>? status;
|
||||||
final int? durationDays;
|
final int? durationDays;
|
||||||
final String? description;
|
final String? description;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
final GetApplicationsByStaffIdApplicationsShiftOrder order;
|
final GetApplicationsByStaffIdApplicationsShiftOrder order;
|
||||||
GetApplicationsByStaffIdApplicationsShift.fromJson(dynamic json):
|
GetApplicationsByStaffIdApplicationsShift.fromJson(dynamic json):
|
||||||
|
|
||||||
@@ -156,6 +158,8 @@ class GetApplicationsByStaffIdApplicationsShift {
|
|||||||
status = json['status'] == null ? null : shiftStatusDeserializer(json['status']),
|
status = json['status'] == null ? null : shiftStatusDeserializer(json['status']),
|
||||||
durationDays = json['durationDays'] == null ? null : nativeFromJson<int>(json['durationDays']),
|
durationDays = json['durationDays'] == null ? null : nativeFromJson<int>(json['durationDays']),
|
||||||
description = json['description'] == null ? null : nativeFromJson<String>(json['description']),
|
description = json['description'] == null ? null : nativeFromJson<String>(json['description']),
|
||||||
|
latitude = json['latitude'] == null ? null : nativeFromJson<double>(json['latitude']),
|
||||||
|
longitude = json['longitude'] == null ? null : nativeFromJson<double>(json['longitude']),
|
||||||
order = GetApplicationsByStaffIdApplicationsShiftOrder.fromJson(json['order']);
|
order = GetApplicationsByStaffIdApplicationsShiftOrder.fromJson(json['order']);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
@@ -176,11 +180,13 @@ class GetApplicationsByStaffIdApplicationsShift {
|
|||||||
status == otherTyped.status &&
|
status == otherTyped.status &&
|
||||||
durationDays == otherTyped.durationDays &&
|
durationDays == otherTyped.durationDays &&
|
||||||
description == otherTyped.description &&
|
description == otherTyped.description &&
|
||||||
|
latitude == otherTyped.latitude &&
|
||||||
|
longitude == otherTyped.longitude &&
|
||||||
order == otherTyped.order;
|
order == otherTyped.order;
|
||||||
|
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, date.hashCode, startTime.hashCode, endTime.hashCode, location.hashCode, status.hashCode, durationDays.hashCode, description.hashCode, order.hashCode]);
|
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, date.hashCode, startTime.hashCode, endTime.hashCode, location.hashCode, status.hashCode, durationDays.hashCode, description.hashCode, latitude.hashCode, longitude.hashCode, order.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@@ -210,6 +216,12 @@ class GetApplicationsByStaffIdApplicationsShift {
|
|||||||
if (description != null) {
|
if (description != null) {
|
||||||
json['description'] = nativeToJson<String?>(description);
|
json['description'] = nativeToJson<String?>(description);
|
||||||
}
|
}
|
||||||
|
if (latitude != null) {
|
||||||
|
json['latitude'] = nativeToJson<double?>(latitude);
|
||||||
|
}
|
||||||
|
if (longitude != null) {
|
||||||
|
json['longitude'] = nativeToJson<double?>(longitude);
|
||||||
|
}
|
||||||
json['order'] = order.toJson();
|
json['order'] = order.toJson();
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@@ -224,6 +236,8 @@ class GetApplicationsByStaffIdApplicationsShift {
|
|||||||
this.status,
|
this.status,
|
||||||
this.durationDays,
|
this.durationDays,
|
||||||
this.description,
|
this.description,
|
||||||
|
this.latitude,
|
||||||
|
this.longitude,
|
||||||
required this.order,
|
required this.order,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,645 @@
|
|||||||
|
part of 'generated.dart';
|
||||||
|
|
||||||
|
class ListCompletedApplicationsByStaffIdVariablesBuilder {
|
||||||
|
String staffId;
|
||||||
|
Optional<int> _offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
Optional<int> _limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
|
||||||
|
final FirebaseDataConnect _dataConnect; ListCompletedApplicationsByStaffIdVariablesBuilder offset(int? t) {
|
||||||
|
_offset.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
ListCompletedApplicationsByStaffIdVariablesBuilder limit(int? t) {
|
||||||
|
_limit.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdVariablesBuilder(this._dataConnect, {required this.staffId,});
|
||||||
|
Deserializer<ListCompletedApplicationsByStaffIdData> dataDeserializer = (dynamic json) => ListCompletedApplicationsByStaffIdData.fromJson(jsonDecode(json));
|
||||||
|
Serializer<ListCompletedApplicationsByStaffIdVariables> varsSerializer = (ListCompletedApplicationsByStaffIdVariables vars) => jsonEncode(vars.toJson());
|
||||||
|
Future<QueryResult<ListCompletedApplicationsByStaffIdData, ListCompletedApplicationsByStaffIdVariables>> execute() {
|
||||||
|
return ref().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryRef<ListCompletedApplicationsByStaffIdData, ListCompletedApplicationsByStaffIdVariables> ref() {
|
||||||
|
ListCompletedApplicationsByStaffIdVariables vars= ListCompletedApplicationsByStaffIdVariables(staffId: staffId,offset: _offset,limit: _limit,);
|
||||||
|
return _dataConnect.query("listCompletedApplicationsByStaffId", dataDeserializer, varsSerializer, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplications {
|
||||||
|
final String id;
|
||||||
|
final String shiftId;
|
||||||
|
final String staffId;
|
||||||
|
final EnumValue<ApplicationStatus> status;
|
||||||
|
final Timestamp? appliedAt;
|
||||||
|
final Timestamp? checkInTime;
|
||||||
|
final Timestamp? checkOutTime;
|
||||||
|
final EnumValue<ApplicationOrigin> origin;
|
||||||
|
final Timestamp? createdAt;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShift shift;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftRole shiftRole;
|
||||||
|
ListCompletedApplicationsByStaffIdApplications.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
shiftId = nativeFromJson<String>(json['shiftId']),
|
||||||
|
staffId = nativeFromJson<String>(json['staffId']),
|
||||||
|
status = applicationStatusDeserializer(json['status']),
|
||||||
|
appliedAt = json['appliedAt'] == null ? null : Timestamp.fromJson(json['appliedAt']),
|
||||||
|
checkInTime = json['checkInTime'] == null ? null : Timestamp.fromJson(json['checkInTime']),
|
||||||
|
checkOutTime = json['checkOutTime'] == null ? null : Timestamp.fromJson(json['checkOutTime']),
|
||||||
|
origin = applicationOriginDeserializer(json['origin']),
|
||||||
|
createdAt = json['createdAt'] == null ? null : Timestamp.fromJson(json['createdAt']),
|
||||||
|
shift = ListCompletedApplicationsByStaffIdApplicationsShift.fromJson(json['shift']),
|
||||||
|
shiftRole = ListCompletedApplicationsByStaffIdApplicationsShiftRole.fromJson(json['shiftRole']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplications otherTyped = other as ListCompletedApplicationsByStaffIdApplications;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
shiftId == otherTyped.shiftId &&
|
||||||
|
staffId == otherTyped.staffId &&
|
||||||
|
status == otherTyped.status &&
|
||||||
|
appliedAt == otherTyped.appliedAt &&
|
||||||
|
checkInTime == otherTyped.checkInTime &&
|
||||||
|
checkOutTime == otherTyped.checkOutTime &&
|
||||||
|
origin == otherTyped.origin &&
|
||||||
|
createdAt == otherTyped.createdAt &&
|
||||||
|
shift == otherTyped.shift &&
|
||||||
|
shiftRole == otherTyped.shiftRole;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, shiftId.hashCode, staffId.hashCode, status.hashCode, appliedAt.hashCode, checkInTime.hashCode, checkOutTime.hashCode, origin.hashCode, createdAt.hashCode, shift.hashCode, shiftRole.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['shiftId'] = nativeToJson<String>(shiftId);
|
||||||
|
json['staffId'] = nativeToJson<String>(staffId);
|
||||||
|
json['status'] =
|
||||||
|
applicationStatusSerializer(status)
|
||||||
|
;
|
||||||
|
if (appliedAt != null) {
|
||||||
|
json['appliedAt'] = appliedAt!.toJson();
|
||||||
|
}
|
||||||
|
if (checkInTime != null) {
|
||||||
|
json['checkInTime'] = checkInTime!.toJson();
|
||||||
|
}
|
||||||
|
if (checkOutTime != null) {
|
||||||
|
json['checkOutTime'] = checkOutTime!.toJson();
|
||||||
|
}
|
||||||
|
json['origin'] =
|
||||||
|
applicationOriginSerializer(origin)
|
||||||
|
;
|
||||||
|
if (createdAt != null) {
|
||||||
|
json['createdAt'] = createdAt!.toJson();
|
||||||
|
}
|
||||||
|
json['shift'] = shift.toJson();
|
||||||
|
json['shiftRole'] = shiftRole.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplications({
|
||||||
|
required this.id,
|
||||||
|
required this.shiftId,
|
||||||
|
required this.staffId,
|
||||||
|
required this.status,
|
||||||
|
this.appliedAt,
|
||||||
|
this.checkInTime,
|
||||||
|
this.checkOutTime,
|
||||||
|
required this.origin,
|
||||||
|
this.createdAt,
|
||||||
|
required this.shift,
|
||||||
|
required this.shiftRole,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShift {
|
||||||
|
final String id;
|
||||||
|
final String title;
|
||||||
|
final Timestamp? date;
|
||||||
|
final Timestamp? startTime;
|
||||||
|
final Timestamp? endTime;
|
||||||
|
final String? location;
|
||||||
|
final EnumValue<ShiftStatus>? status;
|
||||||
|
final String? description;
|
||||||
|
final int? durationDays;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrder order;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShift.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
title = nativeFromJson<String>(json['title']),
|
||||||
|
date = json['date'] == null ? null : Timestamp.fromJson(json['date']),
|
||||||
|
startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']),
|
||||||
|
endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']),
|
||||||
|
location = json['location'] == null ? null : nativeFromJson<String>(json['location']),
|
||||||
|
status = json['status'] == null ? null : shiftStatusDeserializer(json['status']),
|
||||||
|
description = json['description'] == null ? null : nativeFromJson<String>(json['description']),
|
||||||
|
durationDays = json['durationDays'] == null ? null : nativeFromJson<int>(json['durationDays']),
|
||||||
|
order = ListCompletedApplicationsByStaffIdApplicationsShiftOrder.fromJson(json['order']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShift otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShift;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
title == otherTyped.title &&
|
||||||
|
date == otherTyped.date &&
|
||||||
|
startTime == otherTyped.startTime &&
|
||||||
|
endTime == otherTyped.endTime &&
|
||||||
|
location == otherTyped.location &&
|
||||||
|
status == otherTyped.status &&
|
||||||
|
description == otherTyped.description &&
|
||||||
|
durationDays == otherTyped.durationDays &&
|
||||||
|
order == otherTyped.order;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, date.hashCode, startTime.hashCode, endTime.hashCode, location.hashCode, status.hashCode, description.hashCode, durationDays.hashCode, order.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['title'] = nativeToJson<String>(title);
|
||||||
|
if (date != null) {
|
||||||
|
json['date'] = date!.toJson();
|
||||||
|
}
|
||||||
|
if (startTime != null) {
|
||||||
|
json['startTime'] = startTime!.toJson();
|
||||||
|
}
|
||||||
|
if (endTime != null) {
|
||||||
|
json['endTime'] = endTime!.toJson();
|
||||||
|
}
|
||||||
|
if (location != null) {
|
||||||
|
json['location'] = nativeToJson<String?>(location);
|
||||||
|
}
|
||||||
|
if (status != null) {
|
||||||
|
json['status'] =
|
||||||
|
shiftStatusSerializer(status!)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (description != null) {
|
||||||
|
json['description'] = nativeToJson<String?>(description);
|
||||||
|
}
|
||||||
|
if (durationDays != null) {
|
||||||
|
json['durationDays'] = nativeToJson<int?>(durationDays);
|
||||||
|
}
|
||||||
|
json['order'] = order.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShift({
|
||||||
|
required this.id,
|
||||||
|
required this.title,
|
||||||
|
this.date,
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.location,
|
||||||
|
this.status,
|
||||||
|
this.description,
|
||||||
|
this.durationDays,
|
||||||
|
required this.order,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShiftOrder {
|
||||||
|
final String id;
|
||||||
|
final String? eventName;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub teamHub;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness business;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor? vendor;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrder.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
eventName = json['eventName'] == null ? null : nativeFromJson<String>(json['eventName']),
|
||||||
|
teamHub = ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub.fromJson(json['teamHub']),
|
||||||
|
business = ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness.fromJson(json['business']),
|
||||||
|
vendor = json['vendor'] == null ? null : ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor.fromJson(json['vendor']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrder otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShiftOrder;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
eventName == otherTyped.eventName &&
|
||||||
|
teamHub == otherTyped.teamHub &&
|
||||||
|
business == otherTyped.business &&
|
||||||
|
vendor == otherTyped.vendor;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, eventName.hashCode, teamHub.hashCode, business.hashCode, vendor.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
if (eventName != null) {
|
||||||
|
json['eventName'] = nativeToJson<String?>(eventName);
|
||||||
|
}
|
||||||
|
json['teamHub'] = teamHub.toJson();
|
||||||
|
json['business'] = business.toJson();
|
||||||
|
if (vendor != null) {
|
||||||
|
json['vendor'] = vendor!.toJson();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrder({
|
||||||
|
required this.id,
|
||||||
|
this.eventName,
|
||||||
|
required this.teamHub,
|
||||||
|
required this.business,
|
||||||
|
this.vendor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub {
|
||||||
|
final String address;
|
||||||
|
final String? placeId;
|
||||||
|
final String hubName;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub.fromJson(dynamic json):
|
||||||
|
|
||||||
|
address = nativeFromJson<String>(json['address']),
|
||||||
|
placeId = json['placeId'] == null ? null : nativeFromJson<String>(json['placeId']),
|
||||||
|
hubName = nativeFromJson<String>(json['hubName']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub;
|
||||||
|
return address == otherTyped.address &&
|
||||||
|
placeId == otherTyped.placeId &&
|
||||||
|
hubName == otherTyped.hubName;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([address.hashCode, placeId.hashCode, hubName.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['address'] = nativeToJson<String>(address);
|
||||||
|
if (placeId != null) {
|
||||||
|
json['placeId'] = nativeToJson<String?>(placeId);
|
||||||
|
}
|
||||||
|
json['hubName'] = nativeToJson<String>(hubName);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrderTeamHub({
|
||||||
|
required this.address,
|
||||||
|
this.placeId,
|
||||||
|
required this.hubName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness {
|
||||||
|
final String id;
|
||||||
|
final String businessName;
|
||||||
|
final String? email;
|
||||||
|
final String? contactName;
|
||||||
|
final String? companyLogoUrl;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
businessName = nativeFromJson<String>(json['businessName']),
|
||||||
|
email = json['email'] == null ? null : nativeFromJson<String>(json['email']),
|
||||||
|
contactName = json['contactName'] == null ? null : nativeFromJson<String>(json['contactName']),
|
||||||
|
companyLogoUrl = json['companyLogoUrl'] == null ? null : nativeFromJson<String>(json['companyLogoUrl']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
businessName == otherTyped.businessName &&
|
||||||
|
email == otherTyped.email &&
|
||||||
|
contactName == otherTyped.contactName &&
|
||||||
|
companyLogoUrl == otherTyped.companyLogoUrl;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, businessName.hashCode, email.hashCode, contactName.hashCode, companyLogoUrl.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['businessName'] = nativeToJson<String>(businessName);
|
||||||
|
if (email != null) {
|
||||||
|
json['email'] = nativeToJson<String?>(email);
|
||||||
|
}
|
||||||
|
if (contactName != null) {
|
||||||
|
json['contactName'] = nativeToJson<String?>(contactName);
|
||||||
|
}
|
||||||
|
if (companyLogoUrl != null) {
|
||||||
|
json['companyLogoUrl'] = nativeToJson<String?>(companyLogoUrl);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrderBusiness({
|
||||||
|
required this.id,
|
||||||
|
required this.businessName,
|
||||||
|
this.email,
|
||||||
|
this.contactName,
|
||||||
|
this.companyLogoUrl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor {
|
||||||
|
final String id;
|
||||||
|
final String companyName;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
companyName = nativeFromJson<String>(json['companyName']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
companyName == otherTyped.companyName;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, companyName.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['companyName'] = nativeToJson<String>(companyName);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftOrderVendor({
|
||||||
|
required this.id,
|
||||||
|
required this.companyName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShiftRole {
|
||||||
|
final String id;
|
||||||
|
final String roleId;
|
||||||
|
final int count;
|
||||||
|
final int? assigned;
|
||||||
|
final Timestamp? startTime;
|
||||||
|
final Timestamp? endTime;
|
||||||
|
final double? hours;
|
||||||
|
final double? totalValue;
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole role;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftRole.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
roleId = nativeFromJson<String>(json['roleId']),
|
||||||
|
count = nativeFromJson<int>(json['count']),
|
||||||
|
assigned = json['assigned'] == null ? null : nativeFromJson<int>(json['assigned']),
|
||||||
|
startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']),
|
||||||
|
endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']),
|
||||||
|
hours = json['hours'] == null ? null : nativeFromJson<double>(json['hours']),
|
||||||
|
totalValue = json['totalValue'] == null ? null : nativeFromJson<double>(json['totalValue']),
|
||||||
|
role = ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole.fromJson(json['role']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftRole otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShiftRole;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
roleId == otherTyped.roleId &&
|
||||||
|
count == otherTyped.count &&
|
||||||
|
assigned == otherTyped.assigned &&
|
||||||
|
startTime == otherTyped.startTime &&
|
||||||
|
endTime == otherTyped.endTime &&
|
||||||
|
hours == otherTyped.hours &&
|
||||||
|
totalValue == otherTyped.totalValue &&
|
||||||
|
role == otherTyped.role;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, roleId.hashCode, count.hashCode, assigned.hashCode, startTime.hashCode, endTime.hashCode, hours.hashCode, totalValue.hashCode, role.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['roleId'] = nativeToJson<String>(roleId);
|
||||||
|
json['count'] = nativeToJson<int>(count);
|
||||||
|
if (assigned != null) {
|
||||||
|
json['assigned'] = nativeToJson<int?>(assigned);
|
||||||
|
}
|
||||||
|
if (startTime != null) {
|
||||||
|
json['startTime'] = startTime!.toJson();
|
||||||
|
}
|
||||||
|
if (endTime != null) {
|
||||||
|
json['endTime'] = endTime!.toJson();
|
||||||
|
}
|
||||||
|
if (hours != null) {
|
||||||
|
json['hours'] = nativeToJson<double?>(hours);
|
||||||
|
}
|
||||||
|
if (totalValue != null) {
|
||||||
|
json['totalValue'] = nativeToJson<double?>(totalValue);
|
||||||
|
}
|
||||||
|
json['role'] = role.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftRole({
|
||||||
|
required this.id,
|
||||||
|
required this.roleId,
|
||||||
|
required this.count,
|
||||||
|
this.assigned,
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.hours,
|
||||||
|
this.totalValue,
|
||||||
|
required this.role,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
name = nativeFromJson<String>(json['name']),
|
||||||
|
costPerHour = nativeFromJson<double>(json['costPerHour']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole otherTyped = other as ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
name == otherTyped.name &&
|
||||||
|
costPerHour == otherTyped.costPerHour;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, name.hashCode, costPerHour.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['name'] = nativeToJson<String>(name);
|
||||||
|
json['costPerHour'] = nativeToJson<double>(costPerHour);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdApplicationsShiftRoleRole({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdData {
|
||||||
|
final List<ListCompletedApplicationsByStaffIdApplications> applications;
|
||||||
|
ListCompletedApplicationsByStaffIdData.fromJson(dynamic json):
|
||||||
|
|
||||||
|
applications = (json['applications'] as List<dynamic>)
|
||||||
|
.map((e) => ListCompletedApplicationsByStaffIdApplications.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdData otherTyped = other as ListCompletedApplicationsByStaffIdData;
|
||||||
|
return applications == otherTyped.applications;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => applications.hashCode;
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['applications'] = applications.map((e) => e.toJson()).toList();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdData({
|
||||||
|
required this.applications,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ListCompletedApplicationsByStaffIdVariables {
|
||||||
|
final String staffId;
|
||||||
|
late final Optional<int>offset;
|
||||||
|
late final Optional<int>limit;
|
||||||
|
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
|
||||||
|
ListCompletedApplicationsByStaffIdVariables.fromJson(Map<String, dynamic> json):
|
||||||
|
|
||||||
|
staffId = nativeFromJson<String>(json['staffId']) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
offset.value = json['offset'] == null ? null : nativeFromJson<int>(json['offset']);
|
||||||
|
|
||||||
|
|
||||||
|
limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
limit.value = json['limit'] == null ? null : nativeFromJson<int>(json['limit']);
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListCompletedApplicationsByStaffIdVariables otherTyped = other as ListCompletedApplicationsByStaffIdVariables;
|
||||||
|
return staffId == otherTyped.staffId &&
|
||||||
|
offset == otherTyped.offset &&
|
||||||
|
limit == otherTyped.limit;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([staffId.hashCode, offset.hashCode, limit.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['staffId'] = nativeToJson<String>(staffId);
|
||||||
|
if(offset.state == OptionalState.set) {
|
||||||
|
json['offset'] = offset.toJson();
|
||||||
|
}
|
||||||
|
if(limit.state == OptionalState.set) {
|
||||||
|
json['limit'] = limit.toJson();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCompletedApplicationsByStaffIdVariables({
|
||||||
|
required this.staffId,
|
||||||
|
required this.offset,
|
||||||
|
required this.limit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,675 @@
|
|||||||
|
part of 'generated.dart';
|
||||||
|
|
||||||
|
class VaidateDayStaffApplicationVariablesBuilder {
|
||||||
|
String staffId;
|
||||||
|
Optional<int> _offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
Optional<int> _limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
Optional<Timestamp> _dayStart = Optional.optional((json) => json['dayStart'] = Timestamp.fromJson(json['dayStart']), defaultSerializer);
|
||||||
|
Optional<Timestamp> _dayEnd = Optional.optional((json) => json['dayEnd'] = Timestamp.fromJson(json['dayEnd']), defaultSerializer);
|
||||||
|
|
||||||
|
final FirebaseDataConnect _dataConnect; VaidateDayStaffApplicationVariablesBuilder offset(int? t) {
|
||||||
|
_offset.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
VaidateDayStaffApplicationVariablesBuilder limit(int? t) {
|
||||||
|
_limit.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
VaidateDayStaffApplicationVariablesBuilder dayStart(Timestamp? t) {
|
||||||
|
_dayStart.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
VaidateDayStaffApplicationVariablesBuilder dayEnd(Timestamp? t) {
|
||||||
|
_dayEnd.value = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationVariablesBuilder(this._dataConnect, {required this.staffId,});
|
||||||
|
Deserializer<VaidateDayStaffApplicationData> dataDeserializer = (dynamic json) => VaidateDayStaffApplicationData.fromJson(jsonDecode(json));
|
||||||
|
Serializer<VaidateDayStaffApplicationVariables> varsSerializer = (VaidateDayStaffApplicationVariables vars) => jsonEncode(vars.toJson());
|
||||||
|
Future<QueryResult<VaidateDayStaffApplicationData, VaidateDayStaffApplicationVariables>> execute() {
|
||||||
|
return ref().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryRef<VaidateDayStaffApplicationData, VaidateDayStaffApplicationVariables> ref() {
|
||||||
|
VaidateDayStaffApplicationVariables vars= VaidateDayStaffApplicationVariables(staffId: staffId,offset: _offset,limit: _limit,dayStart: _dayStart,dayEnd: _dayEnd,);
|
||||||
|
return _dataConnect.query("vaidateDayStaffApplication", dataDeserializer, varsSerializer, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplications {
|
||||||
|
final String id;
|
||||||
|
final String shiftId;
|
||||||
|
final String staffId;
|
||||||
|
final EnumValue<ApplicationStatus> status;
|
||||||
|
final Timestamp? appliedAt;
|
||||||
|
final Timestamp? checkInTime;
|
||||||
|
final Timestamp? checkOutTime;
|
||||||
|
final EnumValue<ApplicationOrigin> origin;
|
||||||
|
final Timestamp? createdAt;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShift shift;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftRole shiftRole;
|
||||||
|
VaidateDayStaffApplicationApplications.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
shiftId = nativeFromJson<String>(json['shiftId']),
|
||||||
|
staffId = nativeFromJson<String>(json['staffId']),
|
||||||
|
status = applicationStatusDeserializer(json['status']),
|
||||||
|
appliedAt = json['appliedAt'] == null ? null : Timestamp.fromJson(json['appliedAt']),
|
||||||
|
checkInTime = json['checkInTime'] == null ? null : Timestamp.fromJson(json['checkInTime']),
|
||||||
|
checkOutTime = json['checkOutTime'] == null ? null : Timestamp.fromJson(json['checkOutTime']),
|
||||||
|
origin = applicationOriginDeserializer(json['origin']),
|
||||||
|
createdAt = json['createdAt'] == null ? null : Timestamp.fromJson(json['createdAt']),
|
||||||
|
shift = VaidateDayStaffApplicationApplicationsShift.fromJson(json['shift']),
|
||||||
|
shiftRole = VaidateDayStaffApplicationApplicationsShiftRole.fromJson(json['shiftRole']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplications otherTyped = other as VaidateDayStaffApplicationApplications;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
shiftId == otherTyped.shiftId &&
|
||||||
|
staffId == otherTyped.staffId &&
|
||||||
|
status == otherTyped.status &&
|
||||||
|
appliedAt == otherTyped.appliedAt &&
|
||||||
|
checkInTime == otherTyped.checkInTime &&
|
||||||
|
checkOutTime == otherTyped.checkOutTime &&
|
||||||
|
origin == otherTyped.origin &&
|
||||||
|
createdAt == otherTyped.createdAt &&
|
||||||
|
shift == otherTyped.shift &&
|
||||||
|
shiftRole == otherTyped.shiftRole;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, shiftId.hashCode, staffId.hashCode, status.hashCode, appliedAt.hashCode, checkInTime.hashCode, checkOutTime.hashCode, origin.hashCode, createdAt.hashCode, shift.hashCode, shiftRole.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['shiftId'] = nativeToJson<String>(shiftId);
|
||||||
|
json['staffId'] = nativeToJson<String>(staffId);
|
||||||
|
json['status'] =
|
||||||
|
applicationStatusSerializer(status)
|
||||||
|
;
|
||||||
|
if (appliedAt != null) {
|
||||||
|
json['appliedAt'] = appliedAt!.toJson();
|
||||||
|
}
|
||||||
|
if (checkInTime != null) {
|
||||||
|
json['checkInTime'] = checkInTime!.toJson();
|
||||||
|
}
|
||||||
|
if (checkOutTime != null) {
|
||||||
|
json['checkOutTime'] = checkOutTime!.toJson();
|
||||||
|
}
|
||||||
|
json['origin'] =
|
||||||
|
applicationOriginSerializer(origin)
|
||||||
|
;
|
||||||
|
if (createdAt != null) {
|
||||||
|
json['createdAt'] = createdAt!.toJson();
|
||||||
|
}
|
||||||
|
json['shift'] = shift.toJson();
|
||||||
|
json['shiftRole'] = shiftRole.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplications({
|
||||||
|
required this.id,
|
||||||
|
required this.shiftId,
|
||||||
|
required this.staffId,
|
||||||
|
required this.status,
|
||||||
|
this.appliedAt,
|
||||||
|
this.checkInTime,
|
||||||
|
this.checkOutTime,
|
||||||
|
required this.origin,
|
||||||
|
this.createdAt,
|
||||||
|
required this.shift,
|
||||||
|
required this.shiftRole,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShift {
|
||||||
|
final String id;
|
||||||
|
final String title;
|
||||||
|
final Timestamp? date;
|
||||||
|
final Timestamp? startTime;
|
||||||
|
final Timestamp? endTime;
|
||||||
|
final String? location;
|
||||||
|
final EnumValue<ShiftStatus>? status;
|
||||||
|
final int? durationDays;
|
||||||
|
final String? description;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrder order;
|
||||||
|
VaidateDayStaffApplicationApplicationsShift.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
title = nativeFromJson<String>(json['title']),
|
||||||
|
date = json['date'] == null ? null : Timestamp.fromJson(json['date']),
|
||||||
|
startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']),
|
||||||
|
endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']),
|
||||||
|
location = json['location'] == null ? null : nativeFromJson<String>(json['location']),
|
||||||
|
status = json['status'] == null ? null : shiftStatusDeserializer(json['status']),
|
||||||
|
durationDays = json['durationDays'] == null ? null : nativeFromJson<int>(json['durationDays']),
|
||||||
|
description = json['description'] == null ? null : nativeFromJson<String>(json['description']),
|
||||||
|
order = VaidateDayStaffApplicationApplicationsShiftOrder.fromJson(json['order']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShift otherTyped = other as VaidateDayStaffApplicationApplicationsShift;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
title == otherTyped.title &&
|
||||||
|
date == otherTyped.date &&
|
||||||
|
startTime == otherTyped.startTime &&
|
||||||
|
endTime == otherTyped.endTime &&
|
||||||
|
location == otherTyped.location &&
|
||||||
|
status == otherTyped.status &&
|
||||||
|
durationDays == otherTyped.durationDays &&
|
||||||
|
description == otherTyped.description &&
|
||||||
|
order == otherTyped.order;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, date.hashCode, startTime.hashCode, endTime.hashCode, location.hashCode, status.hashCode, durationDays.hashCode, description.hashCode, order.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['title'] = nativeToJson<String>(title);
|
||||||
|
if (date != null) {
|
||||||
|
json['date'] = date!.toJson();
|
||||||
|
}
|
||||||
|
if (startTime != null) {
|
||||||
|
json['startTime'] = startTime!.toJson();
|
||||||
|
}
|
||||||
|
if (endTime != null) {
|
||||||
|
json['endTime'] = endTime!.toJson();
|
||||||
|
}
|
||||||
|
if (location != null) {
|
||||||
|
json['location'] = nativeToJson<String?>(location);
|
||||||
|
}
|
||||||
|
if (status != null) {
|
||||||
|
json['status'] =
|
||||||
|
shiftStatusSerializer(status!)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (durationDays != null) {
|
||||||
|
json['durationDays'] = nativeToJson<int?>(durationDays);
|
||||||
|
}
|
||||||
|
if (description != null) {
|
||||||
|
json['description'] = nativeToJson<String?>(description);
|
||||||
|
}
|
||||||
|
json['order'] = order.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShift({
|
||||||
|
required this.id,
|
||||||
|
required this.title,
|
||||||
|
this.date,
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.location,
|
||||||
|
this.status,
|
||||||
|
this.durationDays,
|
||||||
|
this.description,
|
||||||
|
required this.order,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShiftOrder {
|
||||||
|
final String id;
|
||||||
|
final String? eventName;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrderTeamHub teamHub;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrderBusiness business;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrderVendor? vendor;
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrder.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
eventName = json['eventName'] == null ? null : nativeFromJson<String>(json['eventName']),
|
||||||
|
teamHub = VaidateDayStaffApplicationApplicationsShiftOrderTeamHub.fromJson(json['teamHub']),
|
||||||
|
business = VaidateDayStaffApplicationApplicationsShiftOrderBusiness.fromJson(json['business']),
|
||||||
|
vendor = json['vendor'] == null ? null : VaidateDayStaffApplicationApplicationsShiftOrderVendor.fromJson(json['vendor']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrder otherTyped = other as VaidateDayStaffApplicationApplicationsShiftOrder;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
eventName == otherTyped.eventName &&
|
||||||
|
teamHub == otherTyped.teamHub &&
|
||||||
|
business == otherTyped.business &&
|
||||||
|
vendor == otherTyped.vendor;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, eventName.hashCode, teamHub.hashCode, business.hashCode, vendor.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
if (eventName != null) {
|
||||||
|
json['eventName'] = nativeToJson<String?>(eventName);
|
||||||
|
}
|
||||||
|
json['teamHub'] = teamHub.toJson();
|
||||||
|
json['business'] = business.toJson();
|
||||||
|
if (vendor != null) {
|
||||||
|
json['vendor'] = vendor!.toJson();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrder({
|
||||||
|
required this.id,
|
||||||
|
this.eventName,
|
||||||
|
required this.teamHub,
|
||||||
|
required this.business,
|
||||||
|
this.vendor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShiftOrderTeamHub {
|
||||||
|
final String address;
|
||||||
|
final String? placeId;
|
||||||
|
final String hubName;
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrderTeamHub.fromJson(dynamic json):
|
||||||
|
|
||||||
|
address = nativeFromJson<String>(json['address']),
|
||||||
|
placeId = json['placeId'] == null ? null : nativeFromJson<String>(json['placeId']),
|
||||||
|
hubName = nativeFromJson<String>(json['hubName']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrderTeamHub otherTyped = other as VaidateDayStaffApplicationApplicationsShiftOrderTeamHub;
|
||||||
|
return address == otherTyped.address &&
|
||||||
|
placeId == otherTyped.placeId &&
|
||||||
|
hubName == otherTyped.hubName;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([address.hashCode, placeId.hashCode, hubName.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['address'] = nativeToJson<String>(address);
|
||||||
|
if (placeId != null) {
|
||||||
|
json['placeId'] = nativeToJson<String?>(placeId);
|
||||||
|
}
|
||||||
|
json['hubName'] = nativeToJson<String>(hubName);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrderTeamHub({
|
||||||
|
required this.address,
|
||||||
|
this.placeId,
|
||||||
|
required this.hubName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShiftOrderBusiness {
|
||||||
|
final String id;
|
||||||
|
final String businessName;
|
||||||
|
final String? email;
|
||||||
|
final String? contactName;
|
||||||
|
final String? companyLogoUrl;
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrderBusiness.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
businessName = nativeFromJson<String>(json['businessName']),
|
||||||
|
email = json['email'] == null ? null : nativeFromJson<String>(json['email']),
|
||||||
|
contactName = json['contactName'] == null ? null : nativeFromJson<String>(json['contactName']),
|
||||||
|
companyLogoUrl = json['companyLogoUrl'] == null ? null : nativeFromJson<String>(json['companyLogoUrl']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrderBusiness otherTyped = other as VaidateDayStaffApplicationApplicationsShiftOrderBusiness;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
businessName == otherTyped.businessName &&
|
||||||
|
email == otherTyped.email &&
|
||||||
|
contactName == otherTyped.contactName &&
|
||||||
|
companyLogoUrl == otherTyped.companyLogoUrl;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, businessName.hashCode, email.hashCode, contactName.hashCode, companyLogoUrl.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['businessName'] = nativeToJson<String>(businessName);
|
||||||
|
if (email != null) {
|
||||||
|
json['email'] = nativeToJson<String?>(email);
|
||||||
|
}
|
||||||
|
if (contactName != null) {
|
||||||
|
json['contactName'] = nativeToJson<String?>(contactName);
|
||||||
|
}
|
||||||
|
if (companyLogoUrl != null) {
|
||||||
|
json['companyLogoUrl'] = nativeToJson<String?>(companyLogoUrl);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrderBusiness({
|
||||||
|
required this.id,
|
||||||
|
required this.businessName,
|
||||||
|
this.email,
|
||||||
|
this.contactName,
|
||||||
|
this.companyLogoUrl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShiftOrderVendor {
|
||||||
|
final String id;
|
||||||
|
final String companyName;
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrderVendor.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
companyName = nativeFromJson<String>(json['companyName']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftOrderVendor otherTyped = other as VaidateDayStaffApplicationApplicationsShiftOrderVendor;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
companyName == otherTyped.companyName;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, companyName.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['companyName'] = nativeToJson<String>(companyName);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftOrderVendor({
|
||||||
|
required this.id,
|
||||||
|
required this.companyName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShiftRole {
|
||||||
|
final String id;
|
||||||
|
final String roleId;
|
||||||
|
final int count;
|
||||||
|
final int? assigned;
|
||||||
|
final Timestamp? startTime;
|
||||||
|
final Timestamp? endTime;
|
||||||
|
final double? hours;
|
||||||
|
final double? totalValue;
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftRoleRole role;
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftRole.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
roleId = nativeFromJson<String>(json['roleId']),
|
||||||
|
count = nativeFromJson<int>(json['count']),
|
||||||
|
assigned = json['assigned'] == null ? null : nativeFromJson<int>(json['assigned']),
|
||||||
|
startTime = json['startTime'] == null ? null : Timestamp.fromJson(json['startTime']),
|
||||||
|
endTime = json['endTime'] == null ? null : Timestamp.fromJson(json['endTime']),
|
||||||
|
hours = json['hours'] == null ? null : nativeFromJson<double>(json['hours']),
|
||||||
|
totalValue = json['totalValue'] == null ? null : nativeFromJson<double>(json['totalValue']),
|
||||||
|
role = VaidateDayStaffApplicationApplicationsShiftRoleRole.fromJson(json['role']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftRole otherTyped = other as VaidateDayStaffApplicationApplicationsShiftRole;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
roleId == otherTyped.roleId &&
|
||||||
|
count == otherTyped.count &&
|
||||||
|
assigned == otherTyped.assigned &&
|
||||||
|
startTime == otherTyped.startTime &&
|
||||||
|
endTime == otherTyped.endTime &&
|
||||||
|
hours == otherTyped.hours &&
|
||||||
|
totalValue == otherTyped.totalValue &&
|
||||||
|
role == otherTyped.role;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, roleId.hashCode, count.hashCode, assigned.hashCode, startTime.hashCode, endTime.hashCode, hours.hashCode, totalValue.hashCode, role.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['roleId'] = nativeToJson<String>(roleId);
|
||||||
|
json['count'] = nativeToJson<int>(count);
|
||||||
|
if (assigned != null) {
|
||||||
|
json['assigned'] = nativeToJson<int?>(assigned);
|
||||||
|
}
|
||||||
|
if (startTime != null) {
|
||||||
|
json['startTime'] = startTime!.toJson();
|
||||||
|
}
|
||||||
|
if (endTime != null) {
|
||||||
|
json['endTime'] = endTime!.toJson();
|
||||||
|
}
|
||||||
|
if (hours != null) {
|
||||||
|
json['hours'] = nativeToJson<double?>(hours);
|
||||||
|
}
|
||||||
|
if (totalValue != null) {
|
||||||
|
json['totalValue'] = nativeToJson<double?>(totalValue);
|
||||||
|
}
|
||||||
|
json['role'] = role.toJson();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftRole({
|
||||||
|
required this.id,
|
||||||
|
required this.roleId,
|
||||||
|
required this.count,
|
||||||
|
this.assigned,
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.hours,
|
||||||
|
this.totalValue,
|
||||||
|
required this.role,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationApplicationsShiftRoleRole {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final double costPerHour;
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftRoleRole.fromJson(dynamic json):
|
||||||
|
|
||||||
|
id = nativeFromJson<String>(json['id']),
|
||||||
|
name = nativeFromJson<String>(json['name']),
|
||||||
|
costPerHour = nativeFromJson<double>(json['costPerHour']);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationApplicationsShiftRoleRole otherTyped = other as VaidateDayStaffApplicationApplicationsShiftRoleRole;
|
||||||
|
return id == otherTyped.id &&
|
||||||
|
name == otherTyped.name &&
|
||||||
|
costPerHour == otherTyped.costPerHour;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([id.hashCode, name.hashCode, costPerHour.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['id'] = nativeToJson<String>(id);
|
||||||
|
json['name'] = nativeToJson<String>(name);
|
||||||
|
json['costPerHour'] = nativeToJson<double>(costPerHour);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationApplicationsShiftRoleRole({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.costPerHour,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationData {
|
||||||
|
final List<VaidateDayStaffApplicationApplications> applications;
|
||||||
|
VaidateDayStaffApplicationData.fromJson(dynamic json):
|
||||||
|
|
||||||
|
applications = (json['applications'] as List<dynamic>)
|
||||||
|
.map((e) => VaidateDayStaffApplicationApplications.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationData otherTyped = other as VaidateDayStaffApplicationData;
|
||||||
|
return applications == otherTyped.applications;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => applications.hashCode;
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['applications'] = applications.map((e) => e.toJson()).toList();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationData({
|
||||||
|
required this.applications,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class VaidateDayStaffApplicationVariables {
|
||||||
|
final String staffId;
|
||||||
|
late final Optional<int>offset;
|
||||||
|
late final Optional<int>limit;
|
||||||
|
late final Optional<Timestamp>dayStart;
|
||||||
|
late final Optional<Timestamp>dayEnd;
|
||||||
|
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
|
||||||
|
VaidateDayStaffApplicationVariables.fromJson(Map<String, dynamic> json):
|
||||||
|
|
||||||
|
staffId = nativeFromJson<String>(json['staffId']) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
offset = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
offset.value = json['offset'] == null ? null : nativeFromJson<int>(json['offset']);
|
||||||
|
|
||||||
|
|
||||||
|
limit = Optional.optional(nativeFromJson, nativeToJson);
|
||||||
|
limit.value = json['limit'] == null ? null : nativeFromJson<int>(json['limit']);
|
||||||
|
|
||||||
|
|
||||||
|
dayStart = Optional.optional((json) => json['dayStart'] = Timestamp.fromJson(json['dayStart']), defaultSerializer);
|
||||||
|
dayStart.value = json['dayStart'] == null ? null : Timestamp.fromJson(json['dayStart']);
|
||||||
|
|
||||||
|
|
||||||
|
dayEnd = Optional.optional((json) => json['dayEnd'] = Timestamp.fromJson(json['dayEnd']), defaultSerializer);
|
||||||
|
dayEnd.value = json['dayEnd'] == null ? null : Timestamp.fromJson(json['dayEnd']);
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if(identical(this, other)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(other.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final VaidateDayStaffApplicationVariables otherTyped = other as VaidateDayStaffApplicationVariables;
|
||||||
|
return staffId == otherTyped.staffId &&
|
||||||
|
offset == otherTyped.offset &&
|
||||||
|
limit == otherTyped.limit &&
|
||||||
|
dayStart == otherTyped.dayStart &&
|
||||||
|
dayEnd == otherTyped.dayEnd;
|
||||||
|
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hashAll([staffId.hashCode, offset.hashCode, limit.hashCode, dayStart.hashCode, dayEnd.hashCode]);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> json = {};
|
||||||
|
json['staffId'] = nativeToJson<String>(staffId);
|
||||||
|
if(offset.state == OptionalState.set) {
|
||||||
|
json['offset'] = offset.toJson();
|
||||||
|
}
|
||||||
|
if(limit.state == OptionalState.set) {
|
||||||
|
json['limit'] = limit.toJson();
|
||||||
|
}
|
||||||
|
if(dayStart.state == OptionalState.set) {
|
||||||
|
json['dayStart'] = dayStart.toJson();
|
||||||
|
}
|
||||||
|
if(dayEnd.state == OptionalState.set) {
|
||||||
|
json['dayEnd'] = dayEnd.toJson();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
VaidateDayStaffApplicationVariables({
|
||||||
|
required this.staffId,
|
||||||
|
required this.offset,
|
||||||
|
required this.limit,
|
||||||
|
required this.dayStart,
|
||||||
|
required this.dayEnd,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,31 +1,26 @@
|
|||||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
|
||||||
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
import 'package:krow_core/core.dart';
|
import 'package:krow_core/core.dart';
|
||||||
|
import 'package:krow_data_connect/src/session/staff_session_store.dart';
|
||||||
import '../../domain/repositories/clock_in_repository_interface.dart';
|
import '../../domain/repositories/clock_in_repository_interface.dart';
|
||||||
|
|
||||||
/// Implementation of [ClockInRepositoryInterface] using Firebase Data Connect.
|
/// Implementation of [ClockInRepositoryInterface] using Firebase Data Connect.
|
||||||
class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
||||||
final dc.ExampleConnector _dataConnect;
|
final dc.ExampleConnector _dataConnect;
|
||||||
final firebase.FirebaseAuth _firebaseAuth;
|
final Map<String, String> _shiftToApplicationId = {};
|
||||||
|
|
||||||
ClockInRepositoryImpl({
|
ClockInRepositoryImpl({
|
||||||
required dc.ExampleConnector dataConnect,
|
required dc.ExampleConnector dataConnect,
|
||||||
required firebase.FirebaseAuth firebaseAuth,
|
}) : _dataConnect = dataConnect;
|
||||||
}) : _dataConnect = dataConnect,
|
|
||||||
_firebaseAuth = firebaseAuth;
|
|
||||||
|
|
||||||
Future<String> _getStaffId() async {
|
Future<String> _getStaffId() async {
|
||||||
final firebase.User? user = _firebaseAuth.currentUser;
|
final StaffSession? session = StaffSessionStore.instance.session;
|
||||||
if (user == null) throw Exception('User not authenticated');
|
final String? staffId = session?.staff?.id;
|
||||||
|
if (staffId != null && staffId.isNotEmpty) {
|
||||||
final QueryResult<dc.GetStaffByUserIdData, dc.GetStaffByUserIdVariables> result =
|
return staffId;
|
||||||
await _dataConnect.getStaffByUserId(userId: user.uid).execute();
|
|
||||||
if (result.data.staffs.isEmpty) {
|
|
||||||
throw Exception('Staff profile not found');
|
|
||||||
}
|
}
|
||||||
return result.data.staffs.first.id;
|
throw Exception('Staff session not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to convert Data Connect Timestamp to DateTime
|
/// Helper to convert Data Connect Timestamp to DateTime
|
||||||
@@ -68,81 +63,135 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
|||||||
return Timestamp.fromJson(d.toUtc().toIso8601String());
|
return Timestamp.fromJson(d.toUtc().toIso8601String());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to find today's active application
|
({Timestamp start, Timestamp end}) _utcDayRange(DateTime localDay) {
|
||||||
Future<dc.GetApplicationsByStaffIdApplications?> _getTodaysApplication(String staffId) async {
|
final DateTime dayStartUtc = DateTime.utc(
|
||||||
|
localDay.year,
|
||||||
|
localDay.month,
|
||||||
|
localDay.day,
|
||||||
|
);
|
||||||
|
final DateTime dayEndUtc = DateTime.utc(
|
||||||
|
localDay.year,
|
||||||
|
localDay.month,
|
||||||
|
localDay.day,
|
||||||
|
23,
|
||||||
|
59,
|
||||||
|
59,
|
||||||
|
999,
|
||||||
|
999,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
start: _fromDateTime(dayStartUtc),
|
||||||
|
end: _fromDateTime(dayEndUtc),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to find today's applications ordered with the closest at the end.
|
||||||
|
Future<List<dc.GetApplicationsByStaffIdApplications>> _getTodaysApplications(
|
||||||
|
String staffId,
|
||||||
|
) async {
|
||||||
final DateTime now = DateTime.now();
|
final DateTime now = DateTime.now();
|
||||||
|
final range = _utcDayRange(now);
|
||||||
|
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables>
|
||||||
|
result = await _dataConnect
|
||||||
|
.getApplicationsByStaffId(staffId: staffId)
|
||||||
|
.dayStart(range.start)
|
||||||
|
.dayEnd(range.end)
|
||||||
|
.execute();
|
||||||
|
|
||||||
// Fetch recent applications (assuming meaningful limit)
|
final apps = result.data.applications;
|
||||||
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> result =
|
if (apps.isEmpty) return const [];
|
||||||
await _dataConnect.getApplicationsByStaffId(
|
|
||||||
staffId: staffId,
|
|
||||||
).limit(20).execute();
|
|
||||||
|
|
||||||
|
_shiftToApplicationId
|
||||||
|
..clear()
|
||||||
|
..addEntries(apps.map((app) => MapEntry(app.shiftId, app.id)));
|
||||||
|
|
||||||
|
apps.sort((a, b) {
|
||||||
|
final DateTime? aTime =
|
||||||
|
_toDateTime(a.shift.startTime) ?? _toDateTime(a.shift.date);
|
||||||
|
final DateTime? bTime =
|
||||||
|
_toDateTime(b.shift.startTime) ?? _toDateTime(b.shift.date);
|
||||||
|
if (aTime == null && bTime == null) return 0;
|
||||||
|
if (aTime == null) return -1;
|
||||||
|
if (bTime == null) return 1;
|
||||||
|
final Duration aDiff = aTime.difference(now).abs();
|
||||||
|
final Duration bDiff = bTime.difference(now).abs();
|
||||||
|
return bDiff.compareTo(aDiff); // closest at the end
|
||||||
|
});
|
||||||
|
|
||||||
|
return apps;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.GetApplicationsByStaffIdApplications? _getActiveApplication(
|
||||||
|
List<dc.GetApplicationsByStaffIdApplications> apps,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
return result.data.applications.firstWhere((dc.GetApplicationsByStaffIdApplications app) {
|
return apps.firstWhere((app) {
|
||||||
final DateTime? shiftTime = _toDateTime(app.shift.startTime);
|
final status = app.status.stringValue;
|
||||||
|
return status == 'CHECKED_IN' || status == 'LATE';
|
||||||
if (shiftTime == null) return false;
|
|
||||||
|
|
||||||
final bool isSameDay = shiftTime.year == now.year &&
|
|
||||||
shiftTime.month == now.month &&
|
|
||||||
shiftTime.day == now.day;
|
|
||||||
|
|
||||||
if (!isSameDay) return false;
|
|
||||||
|
|
||||||
// Check Status
|
|
||||||
final dynamic status = app.status.stringValue;
|
|
||||||
return status != 'PENDING' && status != 'REJECTED' && status != 'NO_SHOW' && status != 'CANCELED';
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Shift?> getTodaysShift() async {
|
Future<List<Shift>> getTodaysShifts() async {
|
||||||
final String staffId = await _getStaffId();
|
final String staffId = await _getStaffId();
|
||||||
final dc.GetApplicationsByStaffIdApplications? app = await _getTodaysApplication(staffId);
|
final List<dc.GetApplicationsByStaffIdApplications> apps =
|
||||||
|
await _getTodaysApplications(staffId);
|
||||||
|
if (apps.isEmpty) return const [];
|
||||||
|
|
||||||
if (app == null) return null;
|
final List<Shift> shifts = [];
|
||||||
|
for (final app in apps) {
|
||||||
|
final dc.GetApplicationsByStaffIdApplicationsShift shift = app.shift;
|
||||||
|
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
|
||||||
|
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
|
||||||
|
final DateTime? createdDt = _toDateTime(app.createdAt);
|
||||||
|
|
||||||
final dc.GetApplicationsByStaffIdApplicationsShift shift = app.shift;
|
final String roleName = app.shiftRole.role.name;
|
||||||
|
final String orderName =
|
||||||
|
(shift.order.eventName ?? '').trim().isNotEmpty
|
||||||
|
? shift.order.eventName!
|
||||||
|
: shift.order.business.businessName;
|
||||||
|
final String title = '$roleName - $orderName';
|
||||||
|
shifts.add(
|
||||||
|
Shift(
|
||||||
|
id: shift.id,
|
||||||
|
title: title,
|
||||||
|
clientName: shift.order.business.businessName,
|
||||||
|
logoUrl: shift.order.business.companyLogoUrl ?? '',
|
||||||
|
hourlyRate: app.shiftRole.role.costPerHour,
|
||||||
|
location: shift.location ?? '',
|
||||||
|
locationAddress: shift.order.teamHub.hubName,
|
||||||
|
date: startDt?.toIso8601String() ?? '',
|
||||||
|
startTime: startDt?.toIso8601String() ?? '',
|
||||||
|
endTime: endDt?.toIso8601String() ?? '',
|
||||||
|
createdDate: createdDt?.toIso8601String() ?? '',
|
||||||
|
status: shift.status?.stringValue,
|
||||||
|
description: shift.description,
|
||||||
|
latitude: shift.latitude,
|
||||||
|
longitude: shift.longitude,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final QueryResult<dc.GetShiftByIdData, dc.GetShiftByIdVariables> shiftResult =
|
return shifts;
|
||||||
await _dataConnect.getShiftById(id: shift.id).execute();
|
|
||||||
|
|
||||||
if (shiftResult.data.shift == null) return null;
|
|
||||||
|
|
||||||
final dc.GetShiftByIdShift fullShift = shiftResult.data.shift!;
|
|
||||||
|
|
||||||
return Shift(
|
|
||||||
id: fullShift.id,
|
|
||||||
title: fullShift.title,
|
|
||||||
clientName: fullShift.order.business.businessName,
|
|
||||||
logoUrl: '', // Not available in GetShiftById
|
|
||||||
hourlyRate: 0.0,
|
|
||||||
location: fullShift.location ?? '',
|
|
||||||
locationAddress: fullShift.locationAddress ?? '',
|
|
||||||
date: _toDateTime(fullShift.startTime)?.toIso8601String() ?? '',
|
|
||||||
startTime: _toDateTime(fullShift.startTime)?.toIso8601String() ?? '',
|
|
||||||
endTime: _toDateTime(fullShift.endTime)?.toIso8601String() ?? '',
|
|
||||||
createdDate: _toDateTime(fullShift.createdAt)?.toIso8601String() ?? '',
|
|
||||||
status: fullShift.status?.stringValue,
|
|
||||||
description: fullShift.description,
|
|
||||||
latitude: fullShift.latitude,
|
|
||||||
longitude: fullShift.longitude,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<AttendanceStatus> getAttendanceStatus() async {
|
Future<AttendanceStatus> getAttendanceStatus() async {
|
||||||
final String staffId = await _getStaffId();
|
final String staffId = await _getStaffId();
|
||||||
final dc.GetApplicationsByStaffIdApplications? app = await _getTodaysApplication(staffId);
|
final List<dc.GetApplicationsByStaffIdApplications> apps =
|
||||||
|
await _getTodaysApplications(staffId);
|
||||||
if (app == null) {
|
if (apps.isEmpty) {
|
||||||
return const AttendanceStatus(isCheckedIn: false);
|
return const AttendanceStatus(isCheckedIn: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final dc.GetApplicationsByStaffIdApplications? activeApp =
|
||||||
|
_getActiveApplication(apps);
|
||||||
|
final dc.GetApplicationsByStaffIdApplications app =
|
||||||
|
activeApp ?? apps.last;
|
||||||
|
|
||||||
return ClockInAdapter.toAttendanceStatus(
|
return ClockInAdapter.toAttendanceStatus(
|
||||||
status: app.status.stringValue,
|
status: app.status.stringValue,
|
||||||
checkInTime: _toDateTime(app.checkInTime),
|
checkInTime: _toDateTime(app.checkInTime),
|
||||||
@@ -155,18 +204,24 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
|||||||
Future<AttendanceStatus> clockIn({required String shiftId, String? notes}) async {
|
Future<AttendanceStatus> clockIn({required String shiftId, String? notes}) async {
|
||||||
final String staffId = await _getStaffId();
|
final String staffId = await _getStaffId();
|
||||||
|
|
||||||
final QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> appsResult =
|
final String? cachedAppId = _shiftToApplicationId[shiftId];
|
||||||
await _dataConnect.getApplicationsByStaffId(staffId: staffId).execute();
|
dc.GetApplicationsByStaffIdApplications? app;
|
||||||
|
if (cachedAppId != null) {
|
||||||
|
try {
|
||||||
|
final apps = await _getTodaysApplications(staffId);
|
||||||
|
app = apps.firstWhere((a) => a.id == cachedAppId);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
app ??= (await _getTodaysApplications(staffId))
|
||||||
|
.firstWhere((a) => a.shiftId == shiftId);
|
||||||
|
|
||||||
final dc.GetApplicationsByStaffIdApplications app = appsResult.data.applications.firstWhere((dc.GetApplicationsByStaffIdApplications a) => a.shiftId == shiftId);
|
await _dataConnect
|
||||||
|
.updateApplicationStatus(
|
||||||
await _dataConnect.updateApplicationStatus(
|
id: app.id,
|
||||||
id: app.id,
|
roleId: app.shiftRole.id,
|
||||||
roleId: app.shiftRole.id,
|
)
|
||||||
)
|
.checkInTime(_fromDateTime(DateTime.now()))
|
||||||
.status(dc.ApplicationStatus.CHECKED_IN)
|
.execute();
|
||||||
.checkInTime(_fromDateTime(DateTime.now()))
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return getAttendanceStatus();
|
return getAttendanceStatus();
|
||||||
}
|
}
|
||||||
@@ -175,7 +230,10 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
|||||||
Future<AttendanceStatus> clockOut({String? notes, int? breakTimeMinutes}) async {
|
Future<AttendanceStatus> clockOut({String? notes, int? breakTimeMinutes}) async {
|
||||||
final String staffId = await _getStaffId();
|
final String staffId = await _getStaffId();
|
||||||
|
|
||||||
final dc.GetApplicationsByStaffIdApplications? app = await _getTodaysApplication(staffId);
|
final List<dc.GetApplicationsByStaffIdApplications> apps =
|
||||||
|
await _getTodaysApplications(staffId);
|
||||||
|
final dc.GetApplicationsByStaffIdApplications? app =
|
||||||
|
_getActiveApplication(apps);
|
||||||
if (app == null) throw Exception('No active shift found to clock out');
|
if (app == null) throw Exception('No active shift found to clock out');
|
||||||
|
|
||||||
await _dataConnect.updateApplicationStatus(
|
await _dataConnect.updateApplicationStatus(
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import 'package:krow_domain/krow_domain.dart';
|
|||||||
/// Repository interface for Clock In/Out functionality
|
/// Repository interface for Clock In/Out functionality
|
||||||
abstract class ClockInRepositoryInterface {
|
abstract class ClockInRepositoryInterface {
|
||||||
|
|
||||||
/// Retrieves the shift assigned to the user for the current day.
|
/// Retrieves the shifts assigned to the user for the current day.
|
||||||
/// Returns null if no shift is assigned for today.
|
/// Returns empty list if no shift is assigned for today.
|
||||||
Future<Shift?> getTodaysShift();
|
Future<List<Shift>> getTodaysShifts();
|
||||||
|
|
||||||
/// Gets the current attendance status (e.g., checked in or not, times).
|
/// Gets the current attendance status (e.g., checked in or not, times).
|
||||||
/// This helps in restoring the UI state if the app was killed.
|
/// This helps in restoring the UI state if the app was killed.
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import 'package:krow_core/core.dart';
|
|||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
import '../repositories/clock_in_repository_interface.dart';
|
import '../repositories/clock_in_repository_interface.dart';
|
||||||
|
|
||||||
/// Use case for retrieving the user's scheduled shift for today.
|
/// Use case for retrieving the user's scheduled shifts for today.
|
||||||
class GetTodaysShiftUseCase implements NoInputUseCase<Shift?> {
|
class GetTodaysShiftUseCase implements NoInputUseCase<List<Shift>> {
|
||||||
final ClockInRepositoryInterface _repository;
|
final ClockInRepositoryInterface _repository;
|
||||||
|
|
||||||
GetTodaysShiftUseCase(this._repository);
|
GetTodaysShiftUseCase(this._repository);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Shift?> call() {
|
Future<List<Shift>> call() {
|
||||||
return _repository.getTodaysShift();
|
return _repository.getTodaysShifts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
import '../../domain/usecases/get_todays_shift_usecase.dart';
|
import '../../domain/usecases/get_todays_shift_usecase.dart';
|
||||||
import '../../domain/usecases/get_attendance_status_usecase.dart';
|
import '../../domain/usecases/get_attendance_status_usecase.dart';
|
||||||
import '../../domain/usecases/clock_in_usecase.dart';
|
import '../../domain/usecases/clock_in_usecase.dart';
|
||||||
@@ -29,6 +30,7 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState> {
|
|||||||
_clockOut = clockOut,
|
_clockOut = clockOut,
|
||||||
super(ClockInState(selectedDate: DateTime.now())) {
|
super(ClockInState(selectedDate: DateTime.now())) {
|
||||||
on<ClockInPageLoaded>(_onLoaded);
|
on<ClockInPageLoaded>(_onLoaded);
|
||||||
|
on<ShiftSelected>(_onShiftSelected);
|
||||||
on<DateSelected>(_onDateSelected);
|
on<DateSelected>(_onDateSelected);
|
||||||
on<CheckInRequested>(_onCheckIn);
|
on<CheckInRequested>(_onCheckIn);
|
||||||
on<CheckOutRequested>(_onCheckOut);
|
on<CheckOutRequested>(_onCheckOut);
|
||||||
@@ -46,19 +48,30 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState> {
|
|||||||
) async {
|
) async {
|
||||||
emit(state.copyWith(status: ClockInStatus.loading));
|
emit(state.copyWith(status: ClockInStatus.loading));
|
||||||
try {
|
try {
|
||||||
final shift = await _getTodaysShift();
|
final shifts = await _getTodaysShift();
|
||||||
final status = await _getAttendanceStatus();
|
final status = await _getAttendanceStatus();
|
||||||
|
|
||||||
// Check permissions silently on load? Maybe better to wait for user interaction or specific event
|
// 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
|
// However, if shift exists, we might want to check permission state
|
||||||
|
Shift? selectedShift;
|
||||||
|
if (shifts.isNotEmpty) {
|
||||||
|
if (status.activeShiftId != null) {
|
||||||
|
try {
|
||||||
|
selectedShift =
|
||||||
|
shifts.firstWhere((s) => s.id == status.activeShiftId);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
selectedShift ??= shifts.last;
|
||||||
|
}
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
status: ClockInStatus.success,
|
status: ClockInStatus.success,
|
||||||
todayShift: shift,
|
todayShifts: shifts,
|
||||||
|
selectedShift: selectedShift,
|
||||||
attendance: status,
|
attendance: status,
|
||||||
));
|
));
|
||||||
|
|
||||||
if (shift != null && !status.isCheckedIn) {
|
if (selectedShift != null && !status.isCheckedIn) {
|
||||||
add(RequestLocationPermission());
|
add(RequestLocationPermission());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +112,14 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState> {
|
|||||||
double distance = 0;
|
double distance = 0;
|
||||||
bool isVerified = false; // Require location match by default if shift has location
|
bool isVerified = false; // Require location match by default if shift has location
|
||||||
|
|
||||||
if (state.todayShift != null && state.todayShift!.latitude != null && state.todayShift!.longitude != null) {
|
if (state.selectedShift != null &&
|
||||||
|
state.selectedShift!.latitude != null &&
|
||||||
|
state.selectedShift!.longitude != null) {
|
||||||
distance = Geolocator.distanceBetween(
|
distance = Geolocator.distanceBetween(
|
||||||
position.latitude,
|
position.latitude,
|
||||||
position.longitude,
|
position.longitude,
|
||||||
state.todayShift!.latitude!,
|
state.selectedShift!.latitude!,
|
||||||
state.todayShift!.longitude!,
|
state.selectedShift!.longitude!,
|
||||||
);
|
);
|
||||||
isVerified = distance <= allowedRadiusMeters;
|
isVerified = distance <= allowedRadiusMeters;
|
||||||
} else {
|
} else {
|
||||||
@@ -143,6 +158,16 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onShiftSelected(
|
||||||
|
ShiftSelected event,
|
||||||
|
Emitter<ClockInState> emit,
|
||||||
|
) {
|
||||||
|
emit(state.copyWith(selectedShift: event.shift));
|
||||||
|
if (!state.attendance.isCheckedIn) {
|
||||||
|
_startLocationUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onDateSelected(
|
void _onDateSelected(
|
||||||
DateSelected event,
|
DateSelected event,
|
||||||
Emitter<ClockInState> emit,
|
Emitter<ClockInState> emit,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
|
||||||
abstract class ClockInEvent extends Equatable {
|
abstract class ClockInEvent extends Equatable {
|
||||||
const ClockInEvent();
|
const ClockInEvent();
|
||||||
@@ -10,6 +11,14 @@ abstract class ClockInEvent extends Equatable {
|
|||||||
|
|
||||||
class ClockInPageLoaded extends ClockInEvent {}
|
class ClockInPageLoaded extends ClockInEvent {}
|
||||||
|
|
||||||
|
class ShiftSelected extends ClockInEvent {
|
||||||
|
final Shift shift;
|
||||||
|
const ShiftSelected(this.shift);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [shift];
|
||||||
|
}
|
||||||
|
|
||||||
class DateSelected extends ClockInEvent {
|
class DateSelected extends ClockInEvent {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ enum ClockInStatus { initial, loading, success, failure, actionInProgress }
|
|||||||
|
|
||||||
class ClockInState extends Equatable {
|
class ClockInState extends Equatable {
|
||||||
final ClockInStatus status;
|
final ClockInStatus status;
|
||||||
final Shift? todayShift;
|
final List<Shift> todayShifts;
|
||||||
|
final Shift? selectedShift;
|
||||||
final AttendanceStatus attendance;
|
final AttendanceStatus attendance;
|
||||||
final DateTime selectedDate;
|
final DateTime selectedDate;
|
||||||
final String checkInMode;
|
final String checkInMode;
|
||||||
@@ -22,7 +23,8 @@ class ClockInState extends Equatable {
|
|||||||
|
|
||||||
const ClockInState({
|
const ClockInState({
|
||||||
this.status = ClockInStatus.initial,
|
this.status = ClockInStatus.initial,
|
||||||
this.todayShift,
|
this.todayShifts = const [],
|
||||||
|
this.selectedShift,
|
||||||
this.attendance = const AttendanceStatus(),
|
this.attendance = const AttendanceStatus(),
|
||||||
required this.selectedDate,
|
required this.selectedDate,
|
||||||
this.checkInMode = 'swipe',
|
this.checkInMode = 'swipe',
|
||||||
@@ -37,7 +39,8 @@ class ClockInState extends Equatable {
|
|||||||
|
|
||||||
ClockInState copyWith({
|
ClockInState copyWith({
|
||||||
ClockInStatus? status,
|
ClockInStatus? status,
|
||||||
Shift? todayShift,
|
List<Shift>? todayShifts,
|
||||||
|
Shift? selectedShift,
|
||||||
AttendanceStatus? attendance,
|
AttendanceStatus? attendance,
|
||||||
DateTime? selectedDate,
|
DateTime? selectedDate,
|
||||||
String? checkInMode,
|
String? checkInMode,
|
||||||
@@ -51,7 +54,8 @@ class ClockInState extends Equatable {
|
|||||||
}) {
|
}) {
|
||||||
return ClockInState(
|
return ClockInState(
|
||||||
status: status ?? this.status,
|
status: status ?? this.status,
|
||||||
todayShift: todayShift ?? this.todayShift,
|
todayShifts: todayShifts ?? this.todayShifts,
|
||||||
|
selectedShift: selectedShift ?? this.selectedShift,
|
||||||
attendance: attendance ?? this.attendance,
|
attendance: attendance ?? this.attendance,
|
||||||
selectedDate: selectedDate ?? this.selectedDate,
|
selectedDate: selectedDate ?? this.selectedDate,
|
||||||
checkInMode: checkInMode ?? this.checkInMode,
|
checkInMode: checkInMode ?? this.checkInMode,
|
||||||
@@ -68,7 +72,8 @@ class ClockInState extends Equatable {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [
|
List<Object?> get props => [
|
||||||
status,
|
status,
|
||||||
todayShift,
|
todayShifts,
|
||||||
|
selectedShift,
|
||||||
attendance,
|
attendance,
|
||||||
selectedDate,
|
selectedDate,
|
||||||
checkInMode,
|
checkInMode,
|
||||||
|
|||||||
@@ -46,16 +46,23 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.status == ClockInStatus.loading &&
|
if (state.status == ClockInStatus.loading &&
|
||||||
state.todayShift == null) {
|
state.todayShifts.isEmpty) {
|
||||||
return const Scaffold(
|
return const Scaffold(
|
||||||
body: Center(child: CircularProgressIndicator()),
|
body: Center(child: CircularProgressIndicator()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final todayShift = state.todayShift;
|
final todayShifts = state.todayShifts;
|
||||||
final checkInTime = state.attendance.checkInTime;
|
final selectedShift = state.selectedShift;
|
||||||
final checkOutTime = state.attendance.checkOutTime;
|
final activeShiftId = state.attendance.activeShiftId;
|
||||||
final isCheckedIn = state.attendance.isCheckedIn;
|
final bool isActiveSelected =
|
||||||
|
selectedShift != null && selectedShift.id == activeShiftId;
|
||||||
|
final checkInTime =
|
||||||
|
isActiveSelected ? state.attendance.checkInTime : null;
|
||||||
|
final checkOutTime =
|
||||||
|
isActiveSelected ? state.attendance.checkOutTime : null;
|
||||||
|
final isCheckedIn =
|
||||||
|
state.attendance.isCheckedIn && isActiveSelected;
|
||||||
|
|
||||||
// Format times for display
|
// Format times for display
|
||||||
final checkInStr = checkInTime != null
|
final checkInStr = checkInTime != null
|
||||||
@@ -89,9 +96,9 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Commute Tracker (shows before date selector when applicable)
|
// Commute Tracker (shows before date selector when applicable)
|
||||||
if (todayShift != null)
|
if (selectedShift != null)
|
||||||
CommuteTracker(
|
CommuteTracker(
|
||||||
shift: todayShift,
|
shift: selectedShift,
|
||||||
hasLocationConsent: state.hasLocationConsent,
|
hasLocationConsent: state.hasLocationConsent,
|
||||||
isCommuteModeOn: state.isCommuteModeOn,
|
isCommuteModeOn: state.isCommuteModeOn,
|
||||||
distanceMeters: state.distanceFromVenue,
|
distanceMeters: state.distanceFromVenue,
|
||||||
@@ -125,85 +132,113 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Selected Shift Info Card
|
// Selected Shift Info Card
|
||||||
if (todayShift != null)
|
if (todayShifts.isNotEmpty)
|
||||||
Container(
|
Column(
|
||||||
padding: const EdgeInsets.all(12),
|
children: todayShifts
|
||||||
margin: const EdgeInsets.only(bottom: 16),
|
.map(
|
||||||
decoration: BoxDecoration(
|
(shift) => GestureDetector(
|
||||||
color: Colors.white,
|
onTap: () =>
|
||||||
borderRadius: BorderRadius.circular(12),
|
_bloc.add(ShiftSelected(shift)),
|
||||||
border: Border.all(
|
child: Container(
|
||||||
color: const Color(0xFFE2E8F0),
|
padding: const EdgeInsets.all(12),
|
||||||
), // slate-200
|
margin:
|
||||||
),
|
const EdgeInsets.only(bottom: 12),
|
||||||
child: Row(
|
decoration: BoxDecoration(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
color: Colors.white,
|
||||||
children: [
|
borderRadius: BorderRadius.circular(
|
||||||
Expanded(
|
12,
|
||||||
child: Column(
|
),
|
||||||
crossAxisAlignment:
|
border: Border.all(
|
||||||
CrossAxisAlignment.start,
|
color: shift.id ==
|
||||||
children: [
|
selectedShift?.id
|
||||||
const Text(
|
? AppColors.krowBlue
|
||||||
"TODAY'S SHIFT",
|
: const Color(0xFFE2E8F0),
|
||||||
style: TextStyle(
|
width:
|
||||||
fontSize: 10,
|
shift.id == selectedShift?.id
|
||||||
fontWeight: FontWeight.w600,
|
? 2
|
||||||
color: AppColors.krowBlue,
|
: 1,
|
||||||
letterSpacing: 0.5,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
child: Row(
|
||||||
Text(
|
crossAxisAlignment:
|
||||||
todayShift.title,
|
CrossAxisAlignment.start,
|
||||||
style: const TextStyle(
|
children: [
|
||||||
fontSize: 14,
|
Expanded(
|
||||||
fontWeight: FontWeight.w600,
|
child: Column(
|
||||||
color: Color(
|
crossAxisAlignment:
|
||||||
0xFF1E293B,
|
CrossAxisAlignment.start,
|
||||||
), // slate-800
|
children: [
|
||||||
),
|
Text(
|
||||||
|
shift.id ==
|
||||||
|
selectedShift?.id
|
||||||
|
? "SELECTED SHIFT"
|
||||||
|
: "TODAY'S SHIFT",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight:
|
||||||
|
FontWeight.w600,
|
||||||
|
color: shift.id ==
|
||||||
|
selectedShift?.id
|
||||||
|
? AppColors.krowBlue
|
||||||
|
: AppColors
|
||||||
|
.krowCharcoal,
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
shift.title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight:
|
||||||
|
FontWeight.w600,
|
||||||
|
color: Color(0xFF1E293B),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${shift.clientName} • ${shift.location}",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Color(0xFF64748B),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${_formatTime(shift.startTime)} - ${_formatTime(shift.endTime)}",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Color(0xFF475569),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"\$${shift.hourlyRate}/hr",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.krowBlue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
"${todayShift.clientName} • ${todayShift.location}",
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Color(
|
|
||||||
0xFF64748B,
|
|
||||||
), // slate-500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
Column(
|
.toList(),
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"${_formatTime(todayShift.startTime)} - ${_formatTime(todayShift.endTime)}",
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Color(0xFF475569), // slate-600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"\$${todayShift.hourlyRate}/hr",
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: AppColors.krowBlue,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// Swipe To Check In / Checked Out State / No Shift State
|
// Swipe To Check In / Checked Out State / No Shift State
|
||||||
if (todayShift != null && checkOutTime == null) ...[
|
if (selectedShift != null && checkOutTime == null) ...[
|
||||||
if (!isCheckedIn && !_isCheckInAllowed(todayShift))
|
if (!isCheckedIn &&
|
||||||
|
!_isCheckInAllowed(selectedShift))
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
@@ -229,7 +264,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
"Check-in available at ${_getCheckInAvailabilityTime(todayShift)}",
|
"Check-in available at ${_getCheckInAvailabilityTime(selectedShift)}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Color(0xFF64748B), // slate-500
|
color: Color(0xFF64748B), // slate-500
|
||||||
@@ -252,7 +287,9 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
await _showNFCDialog(context);
|
await _showNFCDialog(context);
|
||||||
} else {
|
} else {
|
||||||
_bloc.add(
|
_bloc.add(
|
||||||
CheckInRequested(shiftId: todayShift.id),
|
CheckInRequested(
|
||||||
|
shiftId: selectedShift.id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -270,7 +307,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
] else if (todayShift != null &&
|
] else if (selectedShift != null &&
|
||||||
checkOutTime != null) ...[
|
checkOutTime != null) ...[
|
||||||
// Shift Completed State
|
// Shift Completed State
|
||||||
Container(
|
Container(
|
||||||
@@ -572,8 +609,8 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
|
|
||||||
// After dialog closes, trigger the event if scan was successful (simulated)
|
// After dialog closes, trigger the event if scan was successful (simulated)
|
||||||
// In real app, we would check the dialog result
|
// In real app, we would check the dialog result
|
||||||
if (scanned && _bloc.state.todayShift != null) {
|
if (scanned && _bloc.state.selectedShift != null) {
|
||||||
_bloc.add(CheckInRequested(shiftId: _bloc.state.todayShift!.id));
|
_bloc.add(CheckInRequested(shiftId: _bloc.state.selectedShift!.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +654,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
|||||||
String _getCheckInAvailabilityTime(Shift shift) {
|
String _getCheckInAvailabilityTime(Shift shift) {
|
||||||
if (shift == null) return '';
|
if (shift == null) return '';
|
||||||
try {
|
try {
|
||||||
final shiftStart = DateTime.parse(shift.endTime);
|
final shiftStart = DateTime.parse(shift.startTime.trim());
|
||||||
final windowStart = shiftStart.subtract(const Duration(minutes: 15));
|
final windowStart = shiftStart.subtract(const Duration(minutes: 15));
|
||||||
return DateFormat('h:mm a').format(windowStart);
|
return DateFormat('h:mm a').format(windowStart);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:firebase_auth/firebase_auth.dart';
|
|
||||||
import 'package:flutter_modular/flutter_modular.dart';
|
import 'package:flutter_modular/flutter_modular.dart';
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||||
|
|
||||||
@@ -18,7 +17,6 @@ class StaffClockInModule extends Module {
|
|||||||
i.add<ClockInRepositoryInterface>(
|
i.add<ClockInRepositoryInterface>(
|
||||||
() => ClockInRepositoryImpl(
|
() => ClockInRepositoryImpl(
|
||||||
dataConnect: ExampleConnector.instance,
|
dataConnect: ExampleConnector.instance,
|
||||||
firebaseAuth: FirebaseAuth.instance,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,55 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Shift>> getHistoryShifts() async {
|
Future<List<Shift>> getHistoryShifts() async {
|
||||||
return _fetchApplications(dc.ApplicationStatus.CHECKED_OUT);
|
try {
|
||||||
|
final staffId = await _getStaffId();
|
||||||
|
final response = await _dataConnect
|
||||||
|
.listCompletedApplicationsByStaffId(staffId: staffId)
|
||||||
|
.execute();
|
||||||
|
final List<Shift> shifts = [];
|
||||||
|
|
||||||
|
for (final app in response.data.applications) {
|
||||||
|
_shiftToAppIdMap[app.shift.id] = app.id;
|
||||||
|
_appToRoleIdMap[app.id] = app.shiftRole.id;
|
||||||
|
|
||||||
|
final String roleName = app.shiftRole.role.name;
|
||||||
|
final String orderName =
|
||||||
|
(app.shift.order.eventName ?? '').trim().isNotEmpty
|
||||||
|
? app.shift.order.eventName!
|
||||||
|
: app.shift.order.business.businessName;
|
||||||
|
final String title = '$roleName - $orderName';
|
||||||
|
final DateTime? shiftDate = _toDateTime(app.shift.date);
|
||||||
|
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
|
||||||
|
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
|
||||||
|
final DateTime? createdDt = _toDateTime(app.createdAt);
|
||||||
|
|
||||||
|
shifts.add(
|
||||||
|
Shift(
|
||||||
|
id: app.shift.id,
|
||||||
|
roleId: app.shiftRole.roleId,
|
||||||
|
title: title,
|
||||||
|
clientName: app.shift.order.business.businessName,
|
||||||
|
logoUrl: app.shift.order.business.companyLogoUrl,
|
||||||
|
hourlyRate: app.shiftRole.role.costPerHour,
|
||||||
|
location: app.shift.location ?? '',
|
||||||
|
locationAddress: app.shift.order.teamHub.hubName,
|
||||||
|
date: shiftDate?.toIso8601String() ?? '',
|
||||||
|
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
|
||||||
|
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
|
||||||
|
createdDate: createdDt?.toIso8601String() ?? '',
|
||||||
|
status: _mapStatus(dc.ApplicationStatus.CHECKED_OUT),
|
||||||
|
description: app.shift.description,
|
||||||
|
durationDays: app.shift.durationDays,
|
||||||
|
requiredSlots: app.shiftRole.count,
|
||||||
|
filledSlots: app.shiftRole.assigned ?? 0,
|
||||||
|
hasApplied: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return shifts;
|
||||||
|
} catch (e) {
|
||||||
|
return <Shift>[];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Shift>> _fetchApplications(
|
Future<List<Shift>> _fetchApplications(
|
||||||
@@ -207,6 +255,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
|
|
||||||
final List<Shift> mappedShifts = [];
|
final List<Shift> mappedShifts = [];
|
||||||
for (final sr in allShiftRoles) {
|
for (final sr in allShiftRoles) {
|
||||||
|
final DateTime? shiftDate = _toDateTime(sr.shift.date);
|
||||||
final startDt = _toDateTime(sr.startTime);
|
final startDt = _toDateTime(sr.startTime);
|
||||||
final endDt = _toDateTime(sr.endTime);
|
final endDt = _toDateTime(sr.endTime);
|
||||||
final createdDt = _toDateTime(sr.createdAt);
|
final createdDt = _toDateTime(sr.createdAt);
|
||||||
@@ -220,7 +269,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
hourlyRate: sr.role.costPerHour,
|
hourlyRate: sr.role.costPerHour,
|
||||||
location: sr.shift.location ?? '',
|
location: sr.shift.location ?? '',
|
||||||
locationAddress: sr.shift.locationAddress ?? '',
|
locationAddress: sr.shift.locationAddress ?? '',
|
||||||
date: startDt?.toIso8601String() ?? '',
|
date: shiftDate?.toIso8601String() ?? '',
|
||||||
startTime: startDt != null
|
startTime: startDt != null
|
||||||
? DateFormat('HH:mm').format(startDt)
|
? DateFormat('HH:mm').format(startDt)
|
||||||
: '',
|
: '',
|
||||||
@@ -371,17 +420,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
|
|
||||||
String targetRoleId = roleId ?? '';
|
String targetRoleId = roleId ?? '';
|
||||||
if (targetRoleId.isEmpty) {
|
if (targetRoleId.isEmpty) {
|
||||||
final rolesResult = await _dataConnect
|
throw Exception('Missing role id.');
|
||||||
.listShiftRolesByShiftId(shiftId: shiftId)
|
|
||||||
.execute();
|
|
||||||
if (rolesResult.data.shiftRoles.isEmpty) {
|
|
||||||
throw Exception('No open roles for this shift');
|
|
||||||
}
|
|
||||||
final sr = rolesResult.data.shiftRoles.firstWhere(
|
|
||||||
(r) => (r.assigned ?? 0) < r.count,
|
|
||||||
orElse: () => rolesResult.data.shiftRoles.first,
|
|
||||||
);
|
|
||||||
targetRoleId = sr.roleId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final roleResult = await _dataConnect
|
final roleResult = await _dataConnect
|
||||||
@@ -391,6 +430,41 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
if (role == null) {
|
if (role == null) {
|
||||||
throw Exception('Shift role not found');
|
throw Exception('Shift role not found');
|
||||||
}
|
}
|
||||||
|
final shiftResult = await _dataConnect.getShiftById(id: shiftId).execute();
|
||||||
|
final shift = shiftResult.data.shift;
|
||||||
|
if (shift == null) {
|
||||||
|
throw Exception('Shift not found');
|
||||||
|
}
|
||||||
|
final DateTime? shiftDate = _toDateTime(shift.date);
|
||||||
|
if (shiftDate != null) {
|
||||||
|
final DateTime dayStartUtc = DateTime.utc(
|
||||||
|
shiftDate.year,
|
||||||
|
shiftDate.month,
|
||||||
|
shiftDate.day,
|
||||||
|
);
|
||||||
|
final DateTime dayEndUtc = DateTime.utc(
|
||||||
|
shiftDate.year,
|
||||||
|
shiftDate.month,
|
||||||
|
shiftDate.day,
|
||||||
|
23,
|
||||||
|
59,
|
||||||
|
59,
|
||||||
|
999,
|
||||||
|
999,
|
||||||
|
);
|
||||||
|
print(
|
||||||
|
'Staff applyForShift: dayStartUtc=${_toTimestamp(dayStartUtc).toJson()} '
|
||||||
|
'dayEndUtc=${_toTimestamp(dayEndUtc).toJson()}',
|
||||||
|
);
|
||||||
|
final dayApplications = await _dataConnect
|
||||||
|
.vaidateDayStaffApplication(staffId: staffId)
|
||||||
|
.dayStart(_toTimestamp(dayStartUtc))
|
||||||
|
.dayEnd(_toTimestamp(dayEndUtc))
|
||||||
|
.execute();
|
||||||
|
if (dayApplications.data.applications.isNotEmpty) {
|
||||||
|
throw Exception('The user already has a shift that day.');
|
||||||
|
}
|
||||||
|
}
|
||||||
final existingApplicationResult = await _dataConnect
|
final existingApplicationResult = await _dataConnect
|
||||||
.getApplicationByStaffShiftAndRole(
|
.getApplicationByStaffShiftAndRole(
|
||||||
staffId: staffId,
|
staffId: staffId,
|
||||||
@@ -406,11 +480,6 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
|
|||||||
throw Exception('This shift is full.');
|
throw Exception('This shift is full.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final shiftResult = await _dataConnect.getShiftById(id: shiftId).execute();
|
|
||||||
final shift = shiftResult.data.shift;
|
|
||||||
if (shift == null) {
|
|
||||||
throw Exception('Shift not found');
|
|
||||||
}
|
|
||||||
final int filled = shift.filled ?? 0;
|
final int filled = shift.filled ?? 0;
|
||||||
|
|
||||||
String? appId;
|
String? appId;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState> {
|
|||||||
required this.getHistoryShifts,
|
required this.getHistoryShifts,
|
||||||
}) : super(ShiftsInitial()) {
|
}) : super(ShiftsInitial()) {
|
||||||
on<LoadShiftsEvent>(_onLoadShifts);
|
on<LoadShiftsEvent>(_onLoadShifts);
|
||||||
|
on<LoadHistoryShiftsEvent>(_onLoadHistoryShifts);
|
||||||
on<LoadShiftsForRangeEvent>(_onLoadShiftsForRange);
|
on<LoadShiftsForRangeEvent>(_onLoadShiftsForRange);
|
||||||
on<FilterAvailableShiftsEvent>(_onFilterAvailableShifts);
|
on<FilterAvailableShiftsEvent>(_onFilterAvailableShifts);
|
||||||
}
|
}
|
||||||
@@ -51,7 +52,6 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState> {
|
|||||||
);
|
);
|
||||||
final pendingResult = await getPendingAssignments();
|
final pendingResult = await getPendingAssignments();
|
||||||
final cancelledResult = await getCancelledShifts();
|
final cancelledResult = await getCancelledShifts();
|
||||||
final historyResult = await getHistoryShifts();
|
|
||||||
|
|
||||||
// Initial available with defaults
|
// Initial available with defaults
|
||||||
final availableResult = await getAvailableShifts(const GetAvailableShiftsArguments());
|
final availableResult = await getAvailableShifts(const GetAvailableShiftsArguments());
|
||||||
@@ -61,7 +61,9 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState> {
|
|||||||
pendingShifts: pendingResult,
|
pendingShifts: pendingResult,
|
||||||
cancelledShifts: cancelledResult,
|
cancelledShifts: cancelledResult,
|
||||||
availableShifts: _filterPastShifts(availableResult),
|
availableShifts: _filterPastShifts(availableResult),
|
||||||
historyShifts: historyResult,
|
historyShifts: const [],
|
||||||
|
historyLoading: false,
|
||||||
|
historyLoaded: false,
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
jobType: 'all',
|
jobType: 'all',
|
||||||
));
|
));
|
||||||
@@ -70,6 +72,27 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onLoadHistoryShifts(
|
||||||
|
LoadHistoryShiftsEvent event,
|
||||||
|
Emitter<ShiftsState> emit,
|
||||||
|
) async {
|
||||||
|
final currentState = state;
|
||||||
|
if (currentState is! ShiftsLoaded) return;
|
||||||
|
if (currentState.historyLoading || currentState.historyLoaded) return;
|
||||||
|
|
||||||
|
emit(currentState.copyWith(historyLoading: true));
|
||||||
|
try {
|
||||||
|
final historyResult = await getHistoryShifts();
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
historyShifts: historyResult,
|
||||||
|
historyLoading: false,
|
||||||
|
historyLoaded: true,
|
||||||
|
));
|
||||||
|
} catch (_) {
|
||||||
|
emit(currentState.copyWith(historyLoading: false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onLoadShiftsForRange(
|
Future<void> _onLoadShiftsForRange(
|
||||||
LoadShiftsForRangeEvent event,
|
LoadShiftsForRangeEvent event,
|
||||||
Emitter<ShiftsState> emit,
|
Emitter<ShiftsState> emit,
|
||||||
@@ -87,7 +110,6 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState> {
|
|||||||
|
|
||||||
final pendingResult = await getPendingAssignments();
|
final pendingResult = await getPendingAssignments();
|
||||||
final cancelledResult = await getCancelledShifts();
|
final cancelledResult = await getCancelledShifts();
|
||||||
final historyResult = await getHistoryShifts();
|
|
||||||
final availableResult =
|
final availableResult =
|
||||||
await getAvailableShifts(const GetAvailableShiftsArguments());
|
await getAvailableShifts(const GetAvailableShiftsArguments());
|
||||||
|
|
||||||
@@ -96,7 +118,9 @@ class ShiftsBloc extends Bloc<ShiftsEvent, ShiftsState> {
|
|||||||
pendingShifts: pendingResult,
|
pendingShifts: pendingResult,
|
||||||
cancelledShifts: cancelledResult,
|
cancelledShifts: cancelledResult,
|
||||||
availableShifts: _filterPastShifts(availableResult),
|
availableShifts: _filterPastShifts(availableResult),
|
||||||
historyShifts: historyResult,
|
historyShifts: const [],
|
||||||
|
historyLoading: false,
|
||||||
|
historyLoaded: false,
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
jobType: 'all',
|
jobType: 'all',
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ sealed class ShiftsEvent extends Equatable {
|
|||||||
|
|
||||||
class LoadShiftsEvent extends ShiftsEvent {}
|
class LoadShiftsEvent extends ShiftsEvent {}
|
||||||
|
|
||||||
|
class LoadHistoryShiftsEvent extends ShiftsEvent {}
|
||||||
|
|
||||||
class LoadShiftsForRangeEvent extends ShiftsEvent {
|
class LoadShiftsForRangeEvent extends ShiftsEvent {
|
||||||
final DateTime start;
|
final DateTime start;
|
||||||
final DateTime end;
|
final DateTime end;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ class ShiftsLoaded extends ShiftsState {
|
|||||||
final List<Shift> cancelledShifts;
|
final List<Shift> cancelledShifts;
|
||||||
final List<Shift> availableShifts;
|
final List<Shift> availableShifts;
|
||||||
final List<Shift> historyShifts;
|
final List<Shift> historyShifts;
|
||||||
|
final bool historyLoading;
|
||||||
|
final bool historyLoaded;
|
||||||
final String searchQuery;
|
final String searchQuery;
|
||||||
final String jobType;
|
final String jobType;
|
||||||
|
|
||||||
@@ -27,6 +29,8 @@ class ShiftsLoaded extends ShiftsState {
|
|||||||
required this.cancelledShifts,
|
required this.cancelledShifts,
|
||||||
required this.availableShifts,
|
required this.availableShifts,
|
||||||
required this.historyShifts,
|
required this.historyShifts,
|
||||||
|
required this.historyLoading,
|
||||||
|
required this.historyLoaded,
|
||||||
required this.searchQuery,
|
required this.searchQuery,
|
||||||
required this.jobType,
|
required this.jobType,
|
||||||
});
|
});
|
||||||
@@ -37,6 +41,8 @@ class ShiftsLoaded extends ShiftsState {
|
|||||||
List<Shift>? cancelledShifts,
|
List<Shift>? cancelledShifts,
|
||||||
List<Shift>? availableShifts,
|
List<Shift>? availableShifts,
|
||||||
List<Shift>? historyShifts,
|
List<Shift>? historyShifts,
|
||||||
|
bool? historyLoading,
|
||||||
|
bool? historyLoaded,
|
||||||
String? searchQuery,
|
String? searchQuery,
|
||||||
String? jobType,
|
String? jobType,
|
||||||
}) {
|
}) {
|
||||||
@@ -46,6 +52,8 @@ class ShiftsLoaded extends ShiftsState {
|
|||||||
cancelledShifts: cancelledShifts ?? this.cancelledShifts,
|
cancelledShifts: cancelledShifts ?? this.cancelledShifts,
|
||||||
availableShifts: availableShifts ?? this.availableShifts,
|
availableShifts: availableShifts ?? this.availableShifts,
|
||||||
historyShifts: historyShifts ?? this.historyShifts,
|
historyShifts: historyShifts ?? this.historyShifts,
|
||||||
|
historyLoading: historyLoading ?? this.historyLoading,
|
||||||
|
historyLoaded: historyLoaded ?? this.historyLoaded,
|
||||||
searchQuery: searchQuery ?? this.searchQuery,
|
searchQuery: searchQuery ?? this.searchQuery,
|
||||||
jobType: jobType ?? this.jobType,
|
jobType: jobType ?? this.jobType,
|
||||||
);
|
);
|
||||||
@@ -58,6 +66,8 @@ class ShiftsLoaded extends ShiftsState {
|
|||||||
cancelledShifts,
|
cancelledShifts,
|
||||||
availableShifts,
|
availableShifts,
|
||||||
historyShifts,
|
historyShifts,
|
||||||
|
historyLoading,
|
||||||
|
historyLoaded,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
jobType,
|
jobType,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -9,12 +9,20 @@ import '../blocs/shift_details/shift_details_bloc.dart';
|
|||||||
import '../blocs/shift_details/shift_details_event.dart';
|
import '../blocs/shift_details/shift_details_event.dart';
|
||||||
import '../blocs/shift_details/shift_details_state.dart';
|
import '../blocs/shift_details/shift_details_state.dart';
|
||||||
|
|
||||||
class ShiftDetailsPage extends StatelessWidget {
|
class ShiftDetailsPage extends StatefulWidget {
|
||||||
final String shiftId;
|
final String shiftId;
|
||||||
final Shift? shift;
|
final Shift? shift;
|
||||||
|
|
||||||
const ShiftDetailsPage({super.key, required this.shiftId, this.shift});
|
const ShiftDetailsPage({super.key, required this.shiftId, this.shift});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ShiftDetailsPage> createState() => _ShiftDetailsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
||||||
|
bool _actionDialogOpen = false;
|
||||||
|
bool _isApplying = false;
|
||||||
|
|
||||||
String _formatTime(String time) {
|
String _formatTime(String time) {
|
||||||
if (time.isEmpty) return '';
|
if (time.isEmpty) return '';
|
||||||
try {
|
try {
|
||||||
@@ -124,10 +132,19 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
return BlocProvider<ShiftDetailsBloc>(
|
return BlocProvider<ShiftDetailsBloc>(
|
||||||
create: (_) =>
|
create: (_) =>
|
||||||
Modular.get<ShiftDetailsBloc>()
|
Modular.get<ShiftDetailsBloc>()
|
||||||
..add(LoadShiftDetailsEvent(shiftId, roleId: shift?.roleId)),
|
..add(
|
||||||
|
LoadShiftDetailsEvent(
|
||||||
|
widget.shiftId,
|
||||||
|
roleId: widget.shift?.roleId,
|
||||||
|
),
|
||||||
|
),
|
||||||
child: BlocListener<ShiftDetailsBloc, ShiftDetailsState>(
|
child: BlocListener<ShiftDetailsBloc, ShiftDetailsState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
|
if (state is ShiftActionSuccess || state is ShiftDetailsError) {
|
||||||
|
_closeActionDialog(context);
|
||||||
|
}
|
||||||
if (state is ShiftActionSuccess) {
|
if (state is ShiftActionSuccess) {
|
||||||
|
_isApplying = false;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(state.message),
|
content: Text(state.message),
|
||||||
@@ -136,7 +153,7 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
Modular.to.navigateToShiftsHome(selectedDate: state.shiftDate);
|
Modular.to.navigateToShiftsHome(selectedDate: state.shiftDate);
|
||||||
} else if (state is ShiftDetailsError) {
|
} else if (state is ShiftDetailsError) {
|
||||||
if (shift == null) {
|
if (_isApplying || widget.shift == null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(state.message),
|
content: Text(state.message),
|
||||||
@@ -144,6 +161,7 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
_isApplying = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: BlocBuilder<ShiftDetailsBloc, ShiftDetailsState>(
|
child: BlocBuilder<ShiftDetailsBloc, ShiftDetailsState>(
|
||||||
@@ -158,7 +176,7 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
if (state is ShiftDetailsLoaded) {
|
if (state is ShiftDetailsLoaded) {
|
||||||
displayShift = state.shift;
|
displayShift = state.shift;
|
||||||
} else {
|
} else {
|
||||||
displayShift = shift;
|
displayShift = widget.shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayShift == null) {
|
if (displayShift == null) {
|
||||||
@@ -474,9 +492,7 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () => _bookShift(
|
onPressed: () => _bookShift(
|
||||||
context,
|
context,
|
||||||
displayShift!.id,
|
displayShift!,
|
||||||
displayShift!.roleId,
|
|
||||||
DateTime.tryParse(displayShift!.date),
|
|
||||||
),
|
),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: const Color(
|
backgroundColor: const Color(
|
||||||
@@ -510,9 +526,7 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
|
|
||||||
void _bookShift(
|
void _bookShift(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String id,
|
Shift shift,
|
||||||
String? roleId,
|
|
||||||
DateTime? date,
|
|
||||||
) {
|
) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -526,9 +540,15 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
BlocProvider.of<ShiftDetailsBloc>(
|
Modular.to.pop();
|
||||||
context,
|
_showApplyingDialog(context, shift);
|
||||||
).add(BookShiftDetailsEvent(id, roleId: roleId, date: date));
|
BlocProvider.of<ShiftDetailsBloc>(context).add(
|
||||||
|
BookShiftDetailsEvent(
|
||||||
|
shift.id,
|
||||||
|
roleId: shift.roleId,
|
||||||
|
date: DateTime.tryParse(shift.date),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
foregroundColor: const Color(0xFF10B981),
|
foregroundColor: const Color(0xFF10B981),
|
||||||
@@ -568,4 +588,62 @@ class ShiftDetailsPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showApplyingDialog(BuildContext context, Shift shift) {
|
||||||
|
if (_actionDialogOpen) return;
|
||||||
|
_actionDialogOpen = true;
|
||||||
|
_isApplying = true;
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
useRootNavigator: true,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
title: const Text('Applying'),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 36,
|
||||||
|
width: 36,
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
shift.title,
|
||||||
|
style: UiTypography.body2b.copyWith(
|
||||||
|
color: UiColors.textPrimary,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
Text(
|
||||||
|
'${_formatDate(shift.date)} • ${_formatTime(shift.startTime)} - ${_formatTime(shift.endTime)}',
|
||||||
|
style: UiTypography.body3r.copyWith(
|
||||||
|
color: UiColors.textSecondary,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
if (shift.clientName.isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
Text(
|
||||||
|
shift.clientName,
|
||||||
|
style: UiTypography.body3r.copyWith(
|
||||||
|
color: UiColors.textSecondary,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).then((_) {
|
||||||
|
_actionDialogOpen = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _closeActionDialog(BuildContext context) {
|
||||||
|
if (!_actionDialogOpen) return;
|
||||||
|
Navigator.of(context, rootNavigator: true).pop();
|
||||||
|
_actionDialogOpen = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
_activeTab = widget.initialTab ?? 'myshifts';
|
_activeTab = widget.initialTab ?? 'myshifts';
|
||||||
_selectedDate = widget.selectedDate;
|
_selectedDate = widget.selectedDate;
|
||||||
_bloc.add(LoadShiftsEvent());
|
_bloc.add(LoadShiftsEvent());
|
||||||
|
if (_activeTab == 'history') {
|
||||||
|
_bloc.add(LoadHistoryShiftsEvent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -67,6 +70,12 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
final List<Shift> historyShifts = (state is ShiftsLoaded)
|
final List<Shift> historyShifts = (state is ShiftsLoaded)
|
||||||
? state.historyShifts
|
? state.historyShifts
|
||||||
: [];
|
: [];
|
||||||
|
final bool historyLoading = (state is ShiftsLoaded)
|
||||||
|
? state.historyLoading
|
||||||
|
: false;
|
||||||
|
final bool historyLoaded = (state is ShiftsLoaded)
|
||||||
|
? state.historyLoaded
|
||||||
|
: false;
|
||||||
|
|
||||||
// Note: "filteredJobs" logic moved to FindShiftsTab
|
// Note: "filteredJobs" logic moved to FindShiftsTab
|
||||||
// Note: Calendar logic moved to MyShiftsTab
|
// Note: Calendar logic moved to MyShiftsTab
|
||||||
@@ -120,6 +129,7 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
"History",
|
"History",
|
||||||
UiIcons.clock,
|
UiIcons.clock,
|
||||||
historyShifts.length,
|
historyShifts.length,
|
||||||
|
showCount: historyLoaded,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -133,11 +143,12 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: _buildTabContent(
|
: _buildTabContent(
|
||||||
myShifts,
|
myShifts,
|
||||||
pendingAssignments,
|
pendingAssignments,
|
||||||
cancelledShifts,
|
cancelledShifts,
|
||||||
availableJobs,
|
availableJobs,
|
||||||
historyShifts,
|
historyShifts,
|
||||||
),
|
historyLoading,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -153,6 +164,7 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
List<Shift> cancelledShifts,
|
List<Shift> cancelledShifts,
|
||||||
List<Shift> availableJobs,
|
List<Shift> availableJobs,
|
||||||
List<Shift> historyShifts,
|
List<Shift> historyShifts,
|
||||||
|
bool historyLoading,
|
||||||
) {
|
) {
|
||||||
switch (_activeTab) {
|
switch (_activeTab) {
|
||||||
case 'myshifts':
|
case 'myshifts':
|
||||||
@@ -165,17 +177,31 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
case 'find':
|
case 'find':
|
||||||
return FindShiftsTab(availableJobs: availableJobs);
|
return FindShiftsTab(availableJobs: availableJobs);
|
||||||
case 'history':
|
case 'history':
|
||||||
|
if (historyLoading) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
return HistoryShiftsTab(historyShifts: historyShifts);
|
return HistoryShiftsTab(historyShifts: historyShifts);
|
||||||
default:
|
default:
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTab(String id, String label, IconData icon, int count) {
|
Widget _buildTab(
|
||||||
|
String id,
|
||||||
|
String label,
|
||||||
|
IconData icon,
|
||||||
|
int count, {
|
||||||
|
bool showCount = true,
|
||||||
|
}) {
|
||||||
final isActive = _activeTab == id;
|
final isActive = _activeTab == id;
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => setState(() => _activeTab = id),
|
onTap: () {
|
||||||
|
setState(() => _activeTab = id);
|
||||||
|
if (id == 'history') {
|
||||||
|
_bloc.add(LoadHistoryShiftsEvent());
|
||||||
|
}
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
|
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -205,27 +231,32 @@ class _ShiftsPageState extends State<ShiftsPage> {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
if (showCount) ...[
|
||||||
Container(
|
const SizedBox(width: 4),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
Container(
|
||||||
constraints: const BoxConstraints(minWidth: 18),
|
padding: const EdgeInsets.symmetric(
|
||||||
decoration: BoxDecoration(
|
horizontal: 6,
|
||||||
color: isActive
|
vertical: 2,
|
||||||
? AppColors.krowBlue.withAlpha((0.1 * 255).round())
|
),
|
||||||
: Colors.white.withAlpha((0.2 * 255).round()),
|
constraints: const BoxConstraints(minWidth: 18),
|
||||||
borderRadius: BorderRadius.circular(999),
|
decoration: BoxDecoration(
|
||||||
),
|
color: isActive
|
||||||
child: Center(
|
? AppColors.krowBlue.withAlpha((0.1 * 255).round())
|
||||||
child: Text(
|
: Colors.white.withAlpha((0.2 * 255).round()),
|
||||||
"$count",
|
borderRadius: BorderRadius.circular(999),
|
||||||
style: TextStyle(
|
),
|
||||||
fontSize: 10,
|
child: Center(
|
||||||
fontWeight: FontWeight.bold,
|
child: Text(
|
||||||
color: isActive ? AppColors.krowBlue : Colors.white,
|
"$count",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: isActive ? AppColors.krowBlue : Colors.white,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -294,6 +294,93 @@ query getApplicationsByStaffId(
|
|||||||
origin
|
origin
|
||||||
createdAt
|
createdAt
|
||||||
|
|
||||||
|
shift {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
date
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
location
|
||||||
|
status
|
||||||
|
durationDays
|
||||||
|
description
|
||||||
|
latitude
|
||||||
|
longitude
|
||||||
|
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
eventName
|
||||||
|
#location
|
||||||
|
|
||||||
|
teamHub {
|
||||||
|
address
|
||||||
|
placeId
|
||||||
|
hubName
|
||||||
|
}
|
||||||
|
|
||||||
|
business {
|
||||||
|
id
|
||||||
|
businessName
|
||||||
|
email
|
||||||
|
contactName
|
||||||
|
companyLogoUrl
|
||||||
|
}
|
||||||
|
vendor {
|
||||||
|
id
|
||||||
|
companyName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftRole {
|
||||||
|
id
|
||||||
|
roleId
|
||||||
|
count
|
||||||
|
assigned
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
hours
|
||||||
|
totalValue
|
||||||
|
role {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
costPerHour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
query vaidateDayStaffApplication(
|
||||||
|
$staffId: UUID!
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
$dayStart: Timestamp
|
||||||
|
$dayEnd: Timestamp
|
||||||
|
) @auth(level: USER) {
|
||||||
|
applications(
|
||||||
|
where: {
|
||||||
|
staffId: { eq: $staffId }
|
||||||
|
shift: {
|
||||||
|
date: { ge: $dayStart, le: $dayEnd }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
shiftId
|
||||||
|
staffId
|
||||||
|
status
|
||||||
|
appliedAt
|
||||||
|
checkInTime
|
||||||
|
checkOutTime
|
||||||
|
origin
|
||||||
|
createdAt
|
||||||
|
|
||||||
shift {
|
shift {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -529,3 +616,88 @@ query listStaffsApplicationsByBusinessForDay(
|
|||||||
staff { id fullName email phone photoUrl }
|
staff { id fullName email phone photoUrl }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# COMPLETED APPLICATIONS BY STAFF (same payload as
|
||||||
|
# getApplicationByStaffShiftAndRole)
|
||||||
|
# ==========================================================
|
||||||
|
query listCompletedApplicationsByStaffId(
|
||||||
|
$staffId: UUID!
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
) @auth(level: USER) {
|
||||||
|
applications(
|
||||||
|
where: {
|
||||||
|
staffId: { eq: $staffId }
|
||||||
|
status: { eq: COMPLETED }
|
||||||
|
}
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
orderBy: { appliedAt: DESC }
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
shiftId
|
||||||
|
staffId
|
||||||
|
status
|
||||||
|
appliedAt
|
||||||
|
checkInTime
|
||||||
|
checkOutTime
|
||||||
|
origin
|
||||||
|
createdAt
|
||||||
|
|
||||||
|
shift {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
date
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
location
|
||||||
|
status
|
||||||
|
description
|
||||||
|
durationDays
|
||||||
|
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
eventName
|
||||||
|
|
||||||
|
teamHub {
|
||||||
|
address
|
||||||
|
placeId
|
||||||
|
hubName
|
||||||
|
}
|
||||||
|
|
||||||
|
business {
|
||||||
|
id
|
||||||
|
businessName
|
||||||
|
email
|
||||||
|
contactName
|
||||||
|
companyLogoUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor {
|
||||||
|
id
|
||||||
|
companyName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftRole {
|
||||||
|
id
|
||||||
|
roleId
|
||||||
|
count
|
||||||
|
assigned
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
hours
|
||||||
|
totalValue
|
||||||
|
|
||||||
|
role {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
costPerHour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user