Merge pull request #330 from Oloodi/307-fix-shift-collapse-behavior-in-order-list

307 fix shift collapse behavior in order list
This commit is contained in:
José Salazar
2026-01-30 00:03:06 -05:00
committed by GitHub
7 changed files with 19775 additions and 19703 deletions

View File

@@ -1,16 +1,16 @@
# Basic Usage # Basic Usage
```dart ```dart
ExampleConnector.instance.getWorkforceById(getWorkforceByIdVariables).execute(); ExampleConnector.instance.createRecentPayment(createRecentPaymentVariables).execute();
ExampleConnector.instance.getWorkforceByVendorAndStaff(getWorkforceByVendorAndStaffVariables).execute(); ExampleConnector.instance.updateRecentPayment(updateRecentPaymentVariables).execute();
ExampleConnector.instance.listWorkforceByVendorId(listWorkforceByVendorIdVariables).execute(); ExampleConnector.instance.deleteRecentPayment(deleteRecentPaymentVariables).execute();
ExampleConnector.instance.listWorkforceByStaffId(listWorkforceByStaffIdVariables).execute(); ExampleConnector.instance.CreateStaff(createStaffVariables).execute();
ExampleConnector.instance.getWorkforceByVendorAndNumber(getWorkforceByVendorAndNumberVariables).execute(); ExampleConnector.instance.UpdateStaff(updateStaffVariables).execute();
ExampleConnector.instance.createEmergencyContact(createEmergencyContactVariables).execute(); ExampleConnector.instance.DeleteStaff(deleteStaffVariables).execute();
ExampleConnector.instance.updateEmergencyContact(updateEmergencyContactVariables).execute(); ExampleConnector.instance.getStaffDocumentByKey(getStaffDocumentByKeyVariables).execute();
ExampleConnector.instance.deleteEmergencyContact(deleteEmergencyContactVariables).execute(); ExampleConnector.instance.listStaffDocumentsByStaffId(listStaffDocumentsByStaffIdVariables).execute();
ExampleConnector.instance.listStaffAvailabilities(listStaffAvailabilitiesVariables).execute(); ExampleConnector.instance.listStaffDocumentsByDocumentType(listStaffDocumentsByDocumentTypeVariables).execute();
ExampleConnector.instance.listStaffAvailabilitiesByStaffId(listStaffAvailabilitiesByStaffIdVariables).execute(); ExampleConnector.instance.listStaffDocumentsByStatus(listStaffDocumentsByStatusVariables).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.listStaffCoursesByCourseId({ ... }) await ExampleConnector.instance.updateAttireOption({ ... })
.offset(...) .itemId(...)
.execute(); .execute();
``` ```

View File

@@ -106,13 +106,15 @@ class ListAcceptedApplicationsByBusinessForDayApplicationsStaff {
final String? email; final String? email;
final String? phone; final String? phone;
final String? photoUrl; final String? photoUrl;
final double? averageRating;
ListAcceptedApplicationsByBusinessForDayApplicationsStaff.fromJson(dynamic json): ListAcceptedApplicationsByBusinessForDayApplicationsStaff.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']), id = nativeFromJson<String>(json['id']),
fullName = nativeFromJson<String>(json['fullName']), fullName = nativeFromJson<String>(json['fullName']),
email = json['email'] == null ? null : nativeFromJson<String>(json['email']), email = json['email'] == null ? null : nativeFromJson<String>(json['email']),
phone = json['phone'] == null ? null : nativeFromJson<String>(json['phone']), phone = json['phone'] == null ? null : nativeFromJson<String>(json['phone']),
photoUrl = json['photoUrl'] == null ? null : nativeFromJson<String>(json['photoUrl']); photoUrl = json['photoUrl'] == null ? null : nativeFromJson<String>(json['photoUrl']),
averageRating = json['averageRating'] == null ? null : nativeFromJson<double>(json['averageRating']);
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
if(identical(this, other)) { if(identical(this, other)) {
@@ -127,11 +129,12 @@ class ListAcceptedApplicationsByBusinessForDayApplicationsStaff {
fullName == otherTyped.fullName && fullName == otherTyped.fullName &&
email == otherTyped.email && email == otherTyped.email &&
phone == otherTyped.phone && phone == otherTyped.phone &&
photoUrl == otherTyped.photoUrl; photoUrl == otherTyped.photoUrl &&
averageRating == otherTyped.averageRating;
} }
@override @override
int get hashCode => Object.hashAll([id.hashCode, fullName.hashCode, email.hashCode, phone.hashCode, photoUrl.hashCode]); int get hashCode => Object.hashAll([id.hashCode, fullName.hashCode, email.hashCode, phone.hashCode, photoUrl.hashCode, averageRating.hashCode]);
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@@ -147,6 +150,9 @@ class ListAcceptedApplicationsByBusinessForDayApplicationsStaff {
if (photoUrl != null) { if (photoUrl != null) {
json['photoUrl'] = nativeToJson<String?>(photoUrl); json['photoUrl'] = nativeToJson<String?>(photoUrl);
} }
if (averageRating != null) {
json['averageRating'] = nativeToJson<double?>(averageRating);
}
return json; return json;
} }
@@ -156,6 +162,7 @@ class ListAcceptedApplicationsByBusinessForDayApplicationsStaff {
this.email, this.email,
this.phone, this.phone,
this.photoUrl, this.photoUrl,
this.averageRating,
}); });
} }

View File

@@ -120,6 +120,8 @@ class ViewOrdersRepositoryImpl implements IViewOrdersRepository {
'worker_name': application.staff.fullName, 'worker_name': application.staff.fullName,
'status': 'confirmed', 'status': 'confirmed',
'photo_url': application.staff.photoUrl, 'photo_url': application.staff.photoUrl,
'phone': application.staff.phone,
'rating': application.staff.averageRating,
}); });
} }
return grouped; return grouped;

View File

@@ -7,6 +7,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.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:url_launcher/url_launcher.dart';
import '../blocs/view_orders_cubit.dart'; import '../blocs/view_orders_cubit.dart';
/// A rich card displaying details of a client order/shift. /// A rich card displaying details of a client order/shift.
@@ -234,14 +235,16 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
onTap: () => _openEditSheet(order: order), onTap: () => _openEditSheet(order: order),
), ),
const SizedBox(width: UiConstants.space2), const SizedBox(width: UiConstants.space2),
_buildHeaderIconButton( if (order.confirmedApps.isNotEmpty)
icon: _expanded _buildHeaderIconButton(
? UiIcons.chevronUp icon: _expanded
: UiIcons.chevronDown, ? UiIcons.chevronUp
color: UiColors.iconSecondary, : UiIcons.chevronDown,
bgColor: UiColors.bgSecondary, color: UiColors.iconSecondary,
onTap: () => setState(() => _expanded = !_expanded), bgColor: UiColors.bgSecondary,
), onTap: () =>
setState(() => _expanded = !_expanded),
),
], ],
), ),
], ],
@@ -269,8 +272,7 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
_buildStatDivider(), _buildStatDivider(),
_buildStatItem( _buildStatItem(
icon: UiIcons.users, icon: UiIcons.users,
value: value: '${order.workersNeeded}',
'${order.filled > 0 ? order.filled : order.workersNeeded}',
label: 'Workers', label: 'Workers',
), ),
], ],
@@ -313,7 +315,7 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'${order.filled}/${order.workersNeeded} Workers Filled', '${order.workersNeeded} Workers Filled',
style: UiTypography.body2m.textPrimary, style: UiTypography.body2m.textPrimary,
), ),
], ],
@@ -485,6 +487,7 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
/// Builds a detailed row for a worker. /// Builds a detailed row for a worker.
Widget _buildWorkerRow(Map<String, dynamic> app) { Widget _buildWorkerRow(Map<String, dynamic> app) {
final String? phone = app['phone'] as String?;
return Container( return Container(
margin: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
@@ -515,9 +518,19 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
const SizedBox(height: 2), const SizedBox(height: 2),
Row( Row(
children: <Widget>[ children: <Widget>[
const Icon(UiIcons.star, size: 10, color: UiColors.accent), if ((app['rating'] as num?) != null &&
const SizedBox(width: 2), (app['rating'] as num) > 0) ...<Widget>[
Text('4.8', style: UiTypography.footnote2r.textSecondary), const Icon(
UiIcons.star,
size: 10,
color: UiColors.accent,
),
const SizedBox(width: 2),
Text(
(app['rating'] as num).toStringAsFixed(1),
style: UiTypography.footnote2r.textSecondary,
),
],
if (app['check_in_time'] != null) ...<Widget>[ if (app['check_in_time'] != null) ...<Widget>[
const SizedBox(width: 8), const SizedBox(width: 8),
Container( Container(
@@ -536,20 +549,70 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
), ),
), ),
), ),
] else if ((app['status'] as String?)?.isNotEmpty ?? false) ...<Widget>[
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 1,
),
decoration: BoxDecoration(
color: UiColors.bgSecondary,
borderRadius: BorderRadius.circular(4),
),
child: Text(
(app['status'] as String).toUpperCase(),
style: UiTypography.titleUppercase4m.copyWith(
color: UiColors.textSecondary,
),
),
),
], ],
], ],
), ),
], ],
), ),
), ),
_buildActionIconButton(icon: UiIcons.phone, onTap: () {}), if (phone != null && phone.isNotEmpty) ...<Widget>[
const SizedBox(width: 8), _buildActionIconButton(
_buildActionIconButton(icon: UiIcons.messageCircle, onTap: () {}), icon: UiIcons.phone,
onTap: () => _confirmAndCall(phone),
),
],
], ],
), ),
); );
} }
Future<void> _confirmAndCall(String phone) async {
final bool? shouldCall = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Call'),
content: Text('Do you want to call $phone?'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Call'),
),
],
);
},
);
if (shouldCall != true) {
return;
}
final Uri uri = Uri(scheme: 'tel', path: phone);
await launchUrl(uri);
}
/// Specialized action button for worker rows. /// Specialized action button for worker rows.
Widget _buildActionIconButton({ Widget _buildActionIconButton({
required IconData icon, required IconData icon,

View File

@@ -389,7 +389,7 @@ query listAcceptedApplicationsByBusinessForDay(
checkInTime checkInTime
checkOutTime checkOutTime
appliedAt appliedAt
staff { id fullName email phone photoUrl } staff { id fullName email phone photoUrl averageRating }
} }
} }