feat: Refine badge and status indicator styling across various client features, including updated colors, borders, and typography, and remove unused action buttons.
This commit is contained in:
@@ -28,11 +28,7 @@ class _ShiftRoleKey {
|
||||
/// A sophisticated bottom sheet for editing an existing order,
|
||||
/// following the Unified Order Flow prototype and matching OneTimeOrderView.
|
||||
class OrderEditSheet extends StatefulWidget {
|
||||
const OrderEditSheet({
|
||||
required this.order,
|
||||
this.onUpdated,
|
||||
super.key,
|
||||
});
|
||||
const OrderEditSheet({required this.order, this.onUpdated, super.key});
|
||||
|
||||
final OrderItem order;
|
||||
final VoidCallback? onUpdated;
|
||||
@@ -57,7 +53,8 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
List<Vendor> _vendors = const <Vendor>[];
|
||||
Vendor? _selectedVendor;
|
||||
List<_RoleOption> _roles = const <_RoleOption>[];
|
||||
List<dc.ListTeamHubsByOwnerIdTeamHubs> _hubs = const <dc.ListTeamHubsByOwnerIdTeamHubs>[];
|
||||
List<dc.ListTeamHubsByOwnerIdTeamHubs> _hubs =
|
||||
const <dc.ListTeamHubsByOwnerIdTeamHubs>[];
|
||||
dc.ListTeamHubsByOwnerIdTeamHubs? _selectedHub;
|
||||
|
||||
String? _shiftId;
|
||||
@@ -111,8 +108,10 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
|
||||
try {
|
||||
final QueryResult<
|
||||
dc.ListShiftRolesByBusinessAndOrderData,
|
||||
dc.ListShiftRolesByBusinessAndOrderVariables> result = await _dataConnect
|
||||
dc.ListShiftRolesByBusinessAndOrderData,
|
||||
dc.ListShiftRolesByBusinessAndOrderVariables
|
||||
>
|
||||
result = await _dataConnect
|
||||
.listShiftRolesByBusinessAndOrder(
|
||||
businessId: businessId,
|
||||
orderId: widget.order.orderId,
|
||||
@@ -139,8 +138,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
_orderNameController.text = firstShift.order.eventName ?? '';
|
||||
_shiftId = shiftRoles.first.shiftId;
|
||||
|
||||
final List<Map<String, dynamic>> positions =
|
||||
shiftRoles.map((dc.ListShiftRolesByBusinessAndOrderShiftRoles role) {
|
||||
final List<Map<String, dynamic>> positions = shiftRoles.map((
|
||||
dc.ListShiftRolesByBusinessAndOrderShiftRoles role,
|
||||
) {
|
||||
return <String, dynamic>{
|
||||
'shiftId': role.shiftId,
|
||||
'roleId': role.roleId,
|
||||
@@ -158,13 +158,12 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
positions.add(_emptyPosition());
|
||||
}
|
||||
|
||||
final List<_ShiftRoleKey> originalShiftRoles =
|
||||
shiftRoles
|
||||
.map(
|
||||
(dc.ListShiftRolesByBusinessAndOrderShiftRoles role) =>
|
||||
_ShiftRoleKey(shiftId: role.shiftId, roleId: role.roleId),
|
||||
)
|
||||
.toList();
|
||||
final List<_ShiftRoleKey> originalShiftRoles = shiftRoles
|
||||
.map(
|
||||
(dc.ListShiftRolesByBusinessAndOrderShiftRoles role) =>
|
||||
_ShiftRoleKey(shiftId: role.shiftId, roleId: role.roleId),
|
||||
)
|
||||
.toList();
|
||||
|
||||
await _loadVendorsAndSelect(firstShift.order.vendorId);
|
||||
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShiftOrderTeamHub
|
||||
@@ -199,8 +198,10 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
|
||||
try {
|
||||
final QueryResult<
|
||||
dc.ListTeamHubsByOwnerIdData,
|
||||
dc.ListTeamHubsByOwnerIdVariables> result = await _dataConnect
|
||||
dc.ListTeamHubsByOwnerIdData,
|
||||
dc.ListTeamHubsByOwnerIdVariables
|
||||
>
|
||||
result = await _dataConnect
|
||||
.listTeamHubsByOwnerId(ownerId: businessId)
|
||||
.execute();
|
||||
|
||||
@@ -257,8 +258,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
|
||||
Future<void> _loadVendorsAndSelect(String? selectedVendorId) async {
|
||||
try {
|
||||
final QueryResult<dc.ListVendorsData, void> result =
|
||||
await _dataConnect.listVendors().execute();
|
||||
final QueryResult<dc.ListVendorsData, void> result = await _dataConnect
|
||||
.listVendors()
|
||||
.execute();
|
||||
final List<Vendor> vendors = result.data.vendors
|
||||
.map(
|
||||
(dc.ListVendorsVendors vendor) => Vendor(
|
||||
@@ -303,10 +305,13 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
|
||||
Future<void> _loadRolesForVendor(String vendorId) async {
|
||||
try {
|
||||
final QueryResult<dc.ListRolesByVendorIdData, dc.ListRolesByVendorIdVariables>
|
||||
result = await _dataConnect
|
||||
.listRolesByVendorId(vendorId: vendorId)
|
||||
.execute();
|
||||
final QueryResult<
|
||||
dc.ListRolesByVendorIdData,
|
||||
dc.ListRolesByVendorIdVariables
|
||||
>
|
||||
result = await _dataConnect
|
||||
.listRolesByVendorId(vendorId: vendorId)
|
||||
.execute();
|
||||
final List<_RoleOption> roles = result.data.roles
|
||||
.map(
|
||||
(dc.ListRolesByVendorIdRoles role) => _RoleOption(
|
||||
@@ -350,8 +355,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
}
|
||||
|
||||
String _breakValueFromDuration(dc.EnumValue<dc.BreakDuration>? breakType) {
|
||||
final dc.BreakDuration? value =
|
||||
breakType is dc.Known<dc.BreakDuration> ? breakType.value : null;
|
||||
final dc.BreakDuration? value = breakType is dc.Known<dc.BreakDuration>
|
||||
? breakType.value
|
||||
: null;
|
||||
switch (value) {
|
||||
case dc.BreakDuration.MIN_10:
|
||||
return 'MIN_10';
|
||||
@@ -450,8 +456,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
final DateTime date = _parseDate(_dateController.text);
|
||||
final DateTime start = _parseTime(date, pos['start_time'].toString());
|
||||
final DateTime end = _parseTime(date, pos['end_time'].toString());
|
||||
final DateTime normalizedEnd =
|
||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||
final DateTime normalizedEnd = end.isBefore(start)
|
||||
? end.add(const Duration(days: 1))
|
||||
: end;
|
||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||
final double rate = _rateForRole(roleId);
|
||||
final int count = pos['count'] as int;
|
||||
@@ -481,8 +488,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
int totalWorkers = 0;
|
||||
double shiftCost = 0;
|
||||
|
||||
final List<_ShiftRoleKey> remainingOriginal =
|
||||
List<_ShiftRoleKey>.from(_originalShiftRoles);
|
||||
final List<_ShiftRoleKey> remainingOriginal = List<_ShiftRoleKey>.from(
|
||||
_originalShiftRoles,
|
||||
);
|
||||
|
||||
for (final Map<String, dynamic> pos in _positions) {
|
||||
final String roleId = pos['roleId']?.toString() ?? '';
|
||||
@@ -492,10 +500,14 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
|
||||
final String shiftId = pos['shiftId']?.toString() ?? _shiftId!;
|
||||
final int count = pos['count'] as int;
|
||||
final DateTime start = _parseTime(orderDate, pos['start_time'].toString());
|
||||
final DateTime start = _parseTime(
|
||||
orderDate,
|
||||
pos['start_time'].toString(),
|
||||
);
|
||||
final DateTime end = _parseTime(orderDate, pos['end_time'].toString());
|
||||
final DateTime normalizedEnd =
|
||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
||||
final DateTime normalizedEnd = end.isBefore(start)
|
||||
? end.add(const Duration(days: 1))
|
||||
: end;
|
||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||
final double rate = _rateForRole(roleId);
|
||||
final double totalValue = rate * hours * count;
|
||||
@@ -516,11 +528,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
.deleteShiftRole(shiftId: shiftId, roleId: originalRoleId)
|
||||
.execute();
|
||||
await _dataConnect
|
||||
.createShiftRole(
|
||||
shiftId: shiftId,
|
||||
roleId: roleId,
|
||||
count: count,
|
||||
)
|
||||
.createShiftRole(shiftId: shiftId, roleId: roleId, count: count)
|
||||
.startTime(_toTimestamp(start))
|
||||
.endTime(_toTimestamp(normalizedEnd))
|
||||
.hours(hours)
|
||||
@@ -542,11 +550,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
}
|
||||
} else {
|
||||
await _dataConnect
|
||||
.createShiftRole(
|
||||
shiftId: shiftId,
|
||||
roleId: roleId,
|
||||
count: count,
|
||||
)
|
||||
.createShiftRole(shiftId: shiftId, roleId: roleId, count: count)
|
||||
.startTime(_toTimestamp(start))
|
||||
.endTime(_toTimestamp(normalizedEnd))
|
||||
.hours(hours)
|
||||
@@ -601,54 +605,6 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _cancelOrder() async {
|
||||
final bool? confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: const Text('Cancel Order'),
|
||||
content: const Text(
|
||||
'Are you sure you want to cancel this order? This action cannot be undone.',
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
child: const Text('No, Keep It'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
style: TextButton.styleFrom(foregroundColor: UiColors.destructive),
|
||||
child: const Text('Yes, Cancel Order'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirm != true) return;
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
try {
|
||||
await _dataConnect.deleteOrder(id: widget.order.orderId).execute();
|
||||
if (mounted) {
|
||||
widget.onUpdated?.call();
|
||||
Navigator.pop(context);
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
message: 'Order cancelled successfully',
|
||||
type: UiSnackbarType.success,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(() => _isLoading = false);
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
message: 'Failed to cancel order',
|
||||
type: UiSnackbarType.error,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _removePosition(int index) {
|
||||
if (_positions.length > 1) {
|
||||
setState(() => _positions.removeAt(index));
|
||||
@@ -766,8 +722,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
size: 18,
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
onChanged:
|
||||
(dc.ListTeamHubsByOwnerIdTeamHubs? hub) {
|
||||
onChanged: (dc.ListTeamHubsByOwnerIdTeamHubs? hub) {
|
||||
if (hub != null) {
|
||||
setState(() {
|
||||
_selectedHub = hub;
|
||||
@@ -775,18 +730,17 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
});
|
||||
}
|
||||
},
|
||||
items: _hubs.map(
|
||||
(dc.ListTeamHubsByOwnerIdTeamHubs hub) {
|
||||
return DropdownMenuItem<
|
||||
dc.ListTeamHubsByOwnerIdTeamHubs>(
|
||||
value: hub,
|
||||
child: Text(
|
||||
hub.hubName,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
items: _hubs.map((dc.ListTeamHubsByOwnerIdTeamHubs hub) {
|
||||
return DropdownMenuItem<
|
||||
dc.ListTeamHubsByOwnerIdTeamHubs
|
||||
>(
|
||||
value: hub,
|
||||
child: Text(
|
||||
hub.hubName,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -810,7 +764,11 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: UiConstants.space2,
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.add, size: 16, color: UiColors.primary),
|
||||
const Icon(
|
||||
UiIcons.add,
|
||||
size: 16,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
Text(
|
||||
'Add Position',
|
||||
style: UiTypography.body2m.primary,
|
||||
@@ -836,21 +794,12 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
label: 'Review ${_positions.length} Positions',
|
||||
onPressed: () => setState(() => _showReview = true),
|
||||
),
|
||||
Padding(
|
||||
const Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
UiConstants.space5,
|
||||
0,
|
||||
UiConstants.space5,
|
||||
MediaQuery.of(context).padding.bottom + UiConstants.space2,
|
||||
),
|
||||
child: UiButton.secondary(
|
||||
text: 'Cancel Entire Order',
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: UiColors.destructive,
|
||||
side: const BorderSide(color: UiColors.destructive),
|
||||
),
|
||||
fullWidth: true,
|
||||
onPressed: _cancelOrder,
|
||||
0,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -863,7 +812,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
padding: const EdgeInsets.fromLTRB(20, 24, 20, 20),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.primary,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(UiConstants.space6)),
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(UiConstants.space6),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
@@ -1279,7 +1230,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
height: MediaQuery.of(context).size.height * 0.95,
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgSecondary,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(UiConstants.space6)),
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(UiConstants.space6),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
@@ -1515,7 +1468,9 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
height: MediaQuery.of(context).size.height * 0.95,
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.primary,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(UiConstants.space6)),
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(UiConstants.space6),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
||||
@@ -203,10 +203,7 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
// Title
|
||||
Text(
|
||||
order.title,
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
Text(order.title, style: UiTypography.headline3b),
|
||||
Row(
|
||||
spacing: UiConstants.space1,
|
||||
children: <Widget>[
|
||||
@@ -224,7 +221,7 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
// Location (Hub name + Address)
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
@@ -234,7 +231,7 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -242,8 +239,9 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
if (order.location.isNotEmpty)
|
||||
Text(
|
||||
order.location,
|
||||
style:
|
||||
UiTypography.footnote1b.textPrimary,
|
||||
style: UiTypography
|
||||
.footnote1b
|
||||
.textSecondary,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -294,27 +292,32 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
// Stats Row
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
_buildStatItem(
|
||||
icon: UiIcons.dollar,
|
||||
value: '\$${cost.round()}',
|
||||
label: t.client_view_orders.card.total,
|
||||
),
|
||||
_buildStatDivider(),
|
||||
_buildStatItem(
|
||||
icon: UiIcons.clock,
|
||||
value: hours.toStringAsFixed(1),
|
||||
label: t.client_view_orders.card.hrs,
|
||||
),
|
||||
_buildStatDivider(),
|
||||
_buildStatItem(
|
||||
icon: UiIcons.users,
|
||||
value: '${order.workersNeeded}',
|
||||
label: t.client_create_order.one_time.workers_label,
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
_buildStatItem(
|
||||
icon: UiIcons.dollar,
|
||||
value: '\$${cost.round()}',
|
||||
label: t.client_view_orders.card.total,
|
||||
),
|
||||
_buildStatDivider(),
|
||||
_buildStatItem(
|
||||
icon: UiIcons.clock,
|
||||
value: hours.toStringAsFixed(1),
|
||||
label: t.client_view_orders.card.hrs,
|
||||
),
|
||||
_buildStatDivider(),
|
||||
_buildStatItem(
|
||||
icon: UiIcons.users,
|
||||
value: '${order.workersNeeded}',
|
||||
label: t.client_create_order.one_time.workers_label,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: UiConstants.space5),
|
||||
@@ -486,16 +489,15 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
padding: const EdgeInsets.all(UiConstants.space3),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgSecondary,
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label.toUpperCase(),
|
||||
style: UiTypography.titleUppercase4m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(time, style: UiTypography.body1b.textPrimary),
|
||||
],
|
||||
),
|
||||
@@ -715,12 +717,12 @@ class _ViewOrderCardState extends State<ViewOrderCard> {
|
||||
required String label,
|
||||
}) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Icon(icon, size: 14, color: UiColors.iconSecondary),
|
||||
const SizedBox(width: 6),
|
||||
Text(value, style: UiTypography.body1b.textPrimary),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user