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:
Achintha Isuru
2026-02-23 12:14:28 -05:00
parent 7136aa7686
commit f453f8aadd
6 changed files with 218 additions and 258 deletions

View File

@@ -205,6 +205,14 @@ class UiTypography {
color: UiColors.textPrimary,
);
/// Headline 3 Bold - Font: Instrument Sans, Size: 22, Height: 1.5 (#121826)
static final TextStyle headline3b = _primaryBase.copyWith(
fontWeight: FontWeight.w600,
fontSize: 20,
height: 1.5,
color: UiColors.textPrimary,
);
/// Headline 4 Medium - Font: Instrument Sans, Size: 22, Height: 1.5 (#121826)
static final TextStyle headline4m = _primaryBase.copyWith(
fontWeight: FontWeight.w500,
@@ -354,6 +362,15 @@ class UiTypography {
color: UiColors.textPrimary,
);
/// Body 3 Bold - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: -0.1 (#121826)
static final TextStyle body3b = _primaryBase.copyWith(
fontWeight: FontWeight.w700,
fontSize: 12,
height: 1.5,
letterSpacing: -0.1,
color: UiColors.textPrimary,
);
/// Body 4 Regular - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: 0.05 (#121826)
static final TextStyle body4r = _primaryBase.copyWith(
fontWeight: FontWeight.w400,

View File

@@ -88,10 +88,6 @@ class _BillingViewState extends State<BillingView> {
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
// ... (APP BAR CODE REMAINS UNCHANGED, BUT I MUST INCLUDE IT OR CHUNK IT CORRECTLY)
// Since I cannot see the headers in this chunk, I will target the _buildContent method instead
// to avoid messing up the whole file structure.
// Wait, I can just replace the build method wrapper.
pinned: true,
expandedHeight: 200.0,
backgroundColor: UiColors.primary,
@@ -227,13 +223,6 @@ class _BillingViewState extends State<BillingView> {
crossAxisAlignment: CrossAxisAlignment.start,
spacing: UiConstants.space4,
children: <Widget>[
UiButton.primary(
text: 'View Pending Timesheets',
leadingIcon: UiIcons.clock,
onPressed: () => Modular.to.pushNamed('${ClientPaths.billing}/timesheets'),
fullWidth: true,
),
const SizedBox(height: UiConstants.space2),
if (state.pendingInvoices.isNotEmpty) ...<Widget>[
PendingInvoicesSection(invoices: state.pendingInvoices),
],

View File

@@ -77,10 +77,11 @@ class _StatCard extends StatelessWidget {
return Container(
padding: const EdgeInsets.all(UiConstants.space3),
decoration: BoxDecoration(
color: UiColors.bgMenu,
color: color.withAlpha(10),
borderRadius: UiConstants.radiusLg,
border: Border.all(
color: UiColors.border,
color: color,
width: 0.75,
),
),
child: Column(

View File

@@ -1,11 +1,8 @@
import 'package:core_localization/core_localization.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:krow_domain/krow_domain.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../blocs/coverage_bloc.dart';
import '../blocs/coverage_event.dart';
import 'package:core_localization/core_localization.dart';
/// List of shifts with their workers.
///
@@ -235,19 +232,6 @@ class _ShiftHeader extends StatelessWidget {
total: total,
coveragePercent: coveragePercent,
),
if (current < total)
Padding(
padding: const EdgeInsets.only(left: UiConstants.space2),
child: UiButton.primary(
text: 'Repost',
size: UiButtonSize.small,
onPressed: () {
ReadContext(context).read<CoverageBloc>().add(
CoverageRepostShiftRequested(shiftId: shiftId),
);
},
),
),
],
),
);
@@ -278,14 +262,14 @@ class _CoverageBadge extends StatelessWidget {
Color text;
if (coveragePercent >= 100) {
bg = UiColors.textSuccess;
text = UiColors.primaryForeground;
bg = UiColors.textSuccess.withAlpha(40);
text = UiColors.textSuccess;
} else if (coveragePercent >= 80) {
bg = UiColors.textWarning;
text = UiColors.primaryForeground;
bg = UiColors.textWarning.withAlpha(40);
text = UiColors.textWarning;
} else {
bg = UiColors.destructive;
text = UiColors.destructiveForeground;
bg = UiColors.destructive.withAlpha(40);
text = UiColors.destructive;
}
return Container(
@@ -295,11 +279,12 @@ class _CoverageBadge extends StatelessWidget {
),
decoration: BoxDecoration(
color: bg,
borderRadius: UiConstants.radiusFull,
border: Border.all(color: text, width: 0.75),
borderRadius: UiConstants.radiusMd,
),
child: Text(
'$current/$total',
style: UiTypography.body3m.copyWith(
style: UiTypography.body3b.copyWith(
color: text,
),
),
@@ -335,92 +320,101 @@ class _WorkerRow extends StatelessWidget {
String statusText;
Color badgeBg;
Color badgeText;
Color badgeBorder;
String badgeLabel;
switch (worker.status) {
case CoverageWorkerStatus.checkedIn:
bg = UiColors.textSuccess.withOpacity(0.1);
bg = UiColors.textSuccess.withAlpha(26);
border = UiColors.textSuccess;
textBg = UiColors.textSuccess.withOpacity(0.2);
textBg = UiColors.textSuccess.withAlpha(51);
textColor = UiColors.textSuccess;
icon = UiIcons.success;
statusText = '✓ Checked In at ${formatTime(worker.checkInTime)}';
badgeBg = UiColors.textSuccess;
badgeText = UiColors.primaryForeground;
badgeBg = UiColors.textSuccess.withAlpha(40);
badgeText = UiColors.textSuccess;
badgeBorder = badgeText;
badgeLabel = 'On Site';
case CoverageWorkerStatus.confirmed:
if (worker.checkInTime == null) {
bg = UiColors.textWarning.withOpacity(0.1);
bg = UiColors.textWarning.withAlpha(26);
border = UiColors.textWarning;
textBg = UiColors.textWarning.withOpacity(0.2);
textBg = UiColors.textWarning.withAlpha(51);
textColor = UiColors.textWarning;
icon = UiIcons.clock;
statusText = 'En Route - Expected $shiftStartTime';
badgeBg = UiColors.textWarning;
badgeText = UiColors.primaryForeground;
badgeBg = UiColors.textWarning.withAlpha(40);
badgeText = UiColors.textWarning;
badgeBorder = badgeText;
badgeLabel = 'En Route';
} else {
bg = UiColors.muted.withOpacity(0.1);
bg = UiColors.muted.withAlpha(26);
border = UiColors.border;
textBg = UiColors.muted.withOpacity(0.2);
textBg = UiColors.muted.withAlpha(51);
textColor = UiColors.textSecondary;
icon = UiIcons.success;
statusText = 'Confirmed';
badgeBg = UiColors.muted;
badgeText = UiColors.textPrimary;
badgeBg = UiColors.textSecondary.withAlpha(40);
badgeText = UiColors.textSecondary;
badgeBorder = badgeText;
badgeLabel = 'Confirmed';
}
case CoverageWorkerStatus.late:
bg = UiColors.destructive.withOpacity(0.1);
bg = UiColors.destructive.withAlpha(26);
border = UiColors.destructive;
textBg = UiColors.destructive.withOpacity(0.2);
textBg = UiColors.destructive.withAlpha(51);
textColor = UiColors.destructive;
icon = UiIcons.warning;
statusText = '⚠ Running Late';
badgeBg = UiColors.destructive;
badgeText = UiColors.destructiveForeground;
badgeBg = UiColors.destructive.withAlpha(40);
badgeText = UiColors.destructive;
badgeBorder = badgeText;
badgeLabel = 'Late';
case CoverageWorkerStatus.checkedOut:
bg = UiColors.muted.withOpacity(0.1);
bg = UiColors.muted.withAlpha(26);
border = UiColors.border;
textBg = UiColors.muted.withOpacity(0.2);
textBg = UiColors.muted.withAlpha(51);
textColor = UiColors.textSecondary;
icon = UiIcons.success;
statusText = 'Checked Out';
badgeBg = UiColors.muted;
badgeText = UiColors.textPrimary;
badgeBg = UiColors.textSecondary.withAlpha(40);
badgeText = UiColors.textSecondary;
badgeBorder = badgeText;
badgeLabel = 'Done';
case CoverageWorkerStatus.noShow:
bg = UiColors.destructive.withOpacity(0.1);
bg = UiColors.destructive.withAlpha(26);
border = UiColors.destructive;
textBg = UiColors.destructive.withOpacity(0.2);
textBg = UiColors.destructive.withAlpha(51);
textColor = UiColors.destructive;
icon = UiIcons.warning;
statusText = 'No Show';
badgeBg = UiColors.destructive;
badgeText = UiColors.destructiveForeground;
badgeBg = UiColors.destructive.withAlpha(40);
badgeText = UiColors.destructive;
badgeBorder = badgeText;
badgeLabel = 'No Show';
case CoverageWorkerStatus.completed:
bg = UiColors.textSuccess.withOpacity(0.1);
border = UiColors.textSuccess;
textBg = UiColors.textSuccess.withOpacity(0.2);
bg = UiColors.iconSuccess.withAlpha(26);
border = UiColors.iconSuccess;
textBg = UiColors.iconSuccess.withAlpha(51);
textColor = UiColors.textSuccess;
icon = UiIcons.success;
statusText = 'Completed';
badgeBg = UiColors.textSuccess;
badgeText = UiColors.primaryForeground;
badgeBg = UiColors.textSuccess.withAlpha(40);
badgeText = UiColors.textSuccess;
badgeBorder = badgeText;
badgeLabel = 'Completed';
case CoverageWorkerStatus.pending:
case CoverageWorkerStatus.accepted:
case CoverageWorkerStatus.rejected:
bg = UiColors.muted.withOpacity(0.1);
bg = UiColors.muted.withAlpha(26);
border = UiColors.border;
textBg = UiColors.muted.withOpacity(0.2);
textBg = UiColors.muted.withAlpha(51);
textColor = UiColors.textSecondary;
icon = UiIcons.clock;
statusText = worker.status.name.toUpperCase();
badgeBg = UiColors.muted;
badgeText = UiColors.textPrimary;
badgeBg = UiColors.textSecondary.withAlpha(40);
badgeText = UiColors.textSecondary;
badgeBorder = badgeText;
badgeLabel = worker.status.name[0].toUpperCase() +
worker.status.name.substring(1);
}
@@ -493,40 +487,42 @@ class _WorkerRow extends StatelessWidget {
),
),
Column(
spacing: UiConstants.space2,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space2,
vertical: UiConstants.space1 / 2,
),
decoration: BoxDecoration(
color: badgeBg,
borderRadius: UiConstants.radiusFull,
),
child: Text(
badgeLabel,
style: UiTypography.footnote2b.copyWith(
color: badgeText,
),
spacing: UiConstants.space2,
children: <Widget>[
Container(
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space2,
vertical: UiConstants.space1 / 2,
),
decoration: BoxDecoration(
color: badgeBg,
borderRadius: UiConstants.radiusMd,
border: Border.all(color: badgeBorder, width: 0.5),
),
child: Text(
badgeLabel,
style: UiTypography.footnote2b.copyWith(
color: badgeText,
),
),
if (worker.status == CoverageWorkerStatus.checkedIn)
UiButton.primary(
text: context.t.client_coverage.worker_row.verify,
size: UiButtonSize.small,
onPressed: () {
UiSnackbar.show(
context,
message: context.t.client_coverage.worker_row.verified_message(
name: worker.name,
),
type: UiSnackbarType.success,
);
},
),
],
),
),
if (worker.status == CoverageWorkerStatus.checkedIn)
UiButton.primary(
text: context.t.client_coverage.worker_row.verify,
size: UiButtonSize.small,
onPressed: () {
UiSnackbar.show(
context,
message:
context.t.client_coverage.worker_row.verified_message(
name: worker.name,
),
type: UiSnackbarType.success,
);
},
),
],
),
],
),
);

View File

@@ -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,

View File

@@ -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),
],
),