#537 (Cost Center)#539 (Hub Manager)
This commit is contained in:
@@ -11,6 +11,8 @@ class HubManagerSelector extends StatelessWidget {
|
||||
required this.hintText,
|
||||
required this.label,
|
||||
this.description,
|
||||
this.noManagersText,
|
||||
this.noneText,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -20,6 +22,8 @@ class HubManagerSelector extends StatelessWidget {
|
||||
final String hintText;
|
||||
final String label;
|
||||
final String? description;
|
||||
final String? noManagersText;
|
||||
final String? noneText;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -107,18 +111,20 @@ class HubManagerSelector extends StatelessWidget {
|
||||
shrinkWrap: true,
|
||||
itemCount: managers.isEmpty ? 2 : managers.length + 1,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final String emptyText = noManagersText ?? 'No hub managers available';
|
||||
final String noneLabel = noneText ?? 'None';
|
||||
if (managers.isEmpty) {
|
||||
if (index == 0) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
child: Text('No hub managers available'),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
child: Text(emptyText),
|
||||
);
|
||||
}
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text('None', style: UiTypography.body1m.textSecondary),
|
||||
title: Text(noneLabel, style: UiTypography.body1m.textSecondary),
|
||||
onTap: () => Navigator.of(context).pop(
|
||||
const OrderManagerUiModel(id: 'NONE', name: 'None'),
|
||||
OrderManagerUiModel(id: 'NONE', name: noneLabel),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -126,9 +132,9 @@ class HubManagerSelector extends StatelessWidget {
|
||||
if (index == managers.length) {
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text('None', style: UiTypography.body1m.textSecondary),
|
||||
title: Text(noneLabel, style: UiTypography.body1m.textSecondary),
|
||||
onTap: () => Navigator.of(context).pop(
|
||||
const OrderManagerUiModel(id: 'NONE', name: 'None'),
|
||||
OrderManagerUiModel(id: 'NONE', name: noneLabel),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -332,6 +332,8 @@ class _OneTimeOrderForm extends StatelessWidget {
|
||||
label: labels.hub_manager_label,
|
||||
description: labels.hub_manager_desc,
|
||||
hintText: labels.hub_manager_hint,
|
||||
noManagersText: labels.hub_manager_empty,
|
||||
noneText: labels.hub_manager_none,
|
||||
managers: hubManagers,
|
||||
selectedManager: selectedHubManager,
|
||||
onChanged: onHubManagerChanged,
|
||||
|
||||
@@ -354,6 +354,8 @@ class _PermanentOrderForm extends StatelessWidget {
|
||||
label: oneTimeLabels.hub_manager_label,
|
||||
description: oneTimeLabels.hub_manager_desc,
|
||||
hintText: oneTimeLabels.hub_manager_hint,
|
||||
noManagersText: oneTimeLabels.hub_manager_empty,
|
||||
noneText: oneTimeLabels.hub_manager_none,
|
||||
managers: hubManagers,
|
||||
selectedManager: selectedHubManager,
|
||||
onChanged: onHubManagerChanged,
|
||||
|
||||
@@ -375,6 +375,8 @@ class _RecurringOrderForm extends StatelessWidget {
|
||||
label: oneTimeLabels.hub_manager_label,
|
||||
description: oneTimeLabels.hub_manager_desc,
|
||||
hintText: oneTimeLabels.hub_manager_hint,
|
||||
noManagersText: oneTimeLabels.hub_manager_empty,
|
||||
noneText: oneTimeLabels.hub_manager_none,
|
||||
managers: hubManagers,
|
||||
selectedManager: selectedHubManager,
|
||||
onChanged: onHubManagerChanged,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
||||
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
||||
@@ -686,7 +687,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Edit Your Order',
|
||||
t.client_view_orders.order_edit_sheet.title,
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
@@ -744,7 +745,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
_buildSectionHeader('ORDER NAME'),
|
||||
UiTextField(
|
||||
controller: _orderNameController,
|
||||
hintText: 'Order name',
|
||||
hintText: t.client_view_orders.order_edit_sheet.order_name_hint,
|
||||
prefixIcon: UiIcons.briefcase,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
@@ -801,7 +802,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'POSITIONS',
|
||||
t.client_view_orders.order_edit_sheet.positions_section,
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
TextButton(
|
||||
@@ -821,7 +822,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
color: UiColors.primary,
|
||||
),
|
||||
Text(
|
||||
'Add Position',
|
||||
t.client_view_orders.order_edit_sheet.add_position,
|
||||
style: UiTypography.body2m.primary,
|
||||
),
|
||||
],
|
||||
@@ -842,7 +843,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
),
|
||||
),
|
||||
_buildBottomAction(
|
||||
label: 'Review ${_positions.length} Positions',
|
||||
label: t.client_view_orders.order_edit_sheet.review_positions(count: _positions.length.toString()),
|
||||
onPressed: () => setState(() => _showReview = true),
|
||||
),
|
||||
const Padding(
|
||||
@@ -859,11 +860,13 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
}
|
||||
|
||||
Widget _buildHubManagerSelector() {
|
||||
final TranslationsClientViewOrdersOrderEditSheetEn oes =
|
||||
t.client_view_orders.order_edit_sheet;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_buildSectionHeader('SHIFT CONTACT'),
|
||||
Text('On-site manager or supervisor for this shift', style: UiTypography.body2r.textSecondary),
|
||||
_buildSectionHeader(oes.shift_contact_section),
|
||||
Text(oes.shift_contact_desc, style: UiTypography.body2r.textSecondary),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
InkWell(
|
||||
onTap: () => _showHubManagerSelector(),
|
||||
@@ -895,7 +898,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Text(
|
||||
_selectedManager?.user.fullName ?? 'Select Contact',
|
||||
_selectedManager?.user.fullName ?? oes.select_contact,
|
||||
style: _selectedManager != null
|
||||
? UiTypography.body1r.textPrimary
|
||||
: UiTypography.body2r.textPlaceholder,
|
||||
@@ -925,7 +928,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
title: Text(
|
||||
'Shift Contact',
|
||||
t.client_view_orders.order_edit_sheet.shift_contact_section,
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||
@@ -939,14 +942,14 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
if (_managers.isEmpty) {
|
||||
if (index == 0) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
child: Text('No hub managers available'),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
child: Text(t.client_view_orders.order_edit_sheet.no_hub_managers),
|
||||
);
|
||||
}
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text('None', style: UiTypography.body1m.textSecondary),
|
||||
title: Text(t.client_view_orders.order_edit_sheet.none, style: UiTypography.body1m.textSecondary),
|
||||
onTap: () => Navigator.of(context).pop(null),
|
||||
);
|
||||
}
|
||||
@@ -954,7 +957,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
if (index == _managers.length) {
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text('None', style: UiTypography.body1m.textSecondary),
|
||||
title: Text(t.client_view_orders.order_edit_sheet.none, style: UiTypography.body1m.textSecondary),
|
||||
onTap: () => Navigator.of(context).pop(null),
|
||||
);
|
||||
}
|
||||
@@ -1014,11 +1017,11 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'One-Time Order',
|
||||
t.client_view_orders.order_edit_sheet.one_time_order_title,
|
||||
style: UiTypography.headline3m.copyWith(color: UiColors.white),
|
||||
),
|
||||
Text(
|
||||
'Refine your staffing needs',
|
||||
t.client_view_orders.order_edit_sheet.refine_subtitle,
|
||||
style: UiTypography.footnote2r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.8),
|
||||
),
|
||||
@@ -1060,7 +1063,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
GestureDetector(
|
||||
onTap: () => _removePosition(index),
|
||||
child: Text(
|
||||
'Remove',
|
||||
t.client_view_orders.order_edit_sheet.remove,
|
||||
style: UiTypography.footnote1m.copyWith(
|
||||
color: UiColors.destructive,
|
||||
),
|
||||
@@ -1071,7 +1074,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
|
||||
_buildDropdownField(
|
||||
hint: 'Select role',
|
||||
hint: t.client_view_orders.order_edit_sheet.select_role_hint,
|
||||
value: pos['roleId'],
|
||||
items: <String>[
|
||||
..._roles.map((_RoleOption role) => role.id),
|
||||
@@ -1106,7 +1109,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: _buildInlineTimeInput(
|
||||
label: 'Start',
|
||||
label: t.client_view_orders.order_edit_sheet.start_label,
|
||||
value: pos['start_time'],
|
||||
onTap: () async {
|
||||
final TimeOfDay? picked = await showTimePicker(
|
||||
@@ -1126,7 +1129,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Expanded(
|
||||
child: _buildInlineTimeInput(
|
||||
label: 'End',
|
||||
label: t.client_view_orders.order_edit_sheet.end_label,
|
||||
value: pos['end_time'],
|
||||
onTap: () async {
|
||||
final TimeOfDay? picked = await showTimePicker(
|
||||
@@ -1149,7 +1152,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Workers',
|
||||
t.client_view_orders.order_edit_sheet.workers_label,
|
||||
style: UiTypography.footnote2r.textSecondary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
@@ -1204,7 +1207,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
const Icon(UiIcons.mapPin, size: 14, color: UiColors.primary),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'Use different location for this position',
|
||||
t.client_view_orders.order_edit_sheet.different_location,
|
||||
style: UiTypography.footnote1m.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
@@ -1228,7 +1231,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'Different Location',
|
||||
t.client_view_orders.order_edit_sheet.different_location_title,
|
||||
style: UiTypography.footnote1m.textSecondary,
|
||||
),
|
||||
],
|
||||
@@ -1246,7 +1249,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
UiTextField(
|
||||
controller: TextEditingController(text: pos['location']),
|
||||
hintText: 'Enter different address',
|
||||
hintText: t.client_view_orders.order_edit_sheet.enter_address_hint,
|
||||
onChanged: (String val) =>
|
||||
_updatePosition(index, 'location', val),
|
||||
),
|
||||
@@ -1257,7 +1260,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
|
||||
_buildSectionHeader('LUNCH BREAK'),
|
||||
_buildDropdownField(
|
||||
hint: 'No Break',
|
||||
hint: t.client_view_orders.order_edit_sheet.no_break,
|
||||
value: pos['lunch_break'],
|
||||
items: <String>[
|
||||
'NO_BREAK',
|
||||
@@ -1280,7 +1283,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
case 'MIN_60':
|
||||
return '60 min (Unpaid)';
|
||||
default:
|
||||
return 'No Break';
|
||||
return t.client_view_orders.order_edit_sheet.no_break;
|
||||
}
|
||||
},
|
||||
onChanged: (dynamic val) =>
|
||||
@@ -1438,11 +1441,11 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
_buildSummaryItem('${_positions.length}', 'Positions'),
|
||||
_buildSummaryItem('$totalWorkers', 'Workers'),
|
||||
_buildSummaryItem('${_positions.length}', t.client_view_orders.order_edit_sheet.positions),
|
||||
_buildSummaryItem('$totalWorkers', t.client_view_orders.order_edit_sheet.workers),
|
||||
_buildSummaryItem(
|
||||
'\$${totalCost.round()}',
|
||||
'Est. Cost',
|
||||
t.client_view_orders.order_edit_sheet.est_cost,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1501,7 +1504,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
const SizedBox(height: 24),
|
||||
|
||||
Text(
|
||||
'Positions Breakdown',
|
||||
t.client_view_orders.order_edit_sheet.positions_breakdown,
|
||||
style: UiTypography.body2b.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -1532,14 +1535,14 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: UiButton.secondary(
|
||||
text: 'Edit',
|
||||
text: t.client_view_orders.order_edit_sheet.edit_button,
|
||||
onPressed: () => setState(() => _showReview = false),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UiButton.primary(
|
||||
text: 'Confirm & Save',
|
||||
text: t.client_view_orders.order_edit_sheet.confirm_save,
|
||||
onPressed: () async {
|
||||
setState(() => _isLoading = true);
|
||||
await _saveOrderChanges();
|
||||
@@ -1601,7 +1604,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
(role?.name ?? pos['roleName']?.toString() ?? '').isEmpty
|
||||
? 'Position'
|
||||
? t.client_view_orders.order_edit_sheet.position_singular
|
||||
: (role?.name ?? pos['roleName']?.toString() ?? ''),
|
||||
style: UiTypography.body2b.textPrimary,
|
||||
),
|
||||
@@ -1667,14 +1670,14 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Order Updated!',
|
||||
t.client_view_orders.order_edit_sheet.order_updated_title,
|
||||
style: UiTypography.headline1m.copyWith(color: UiColors.white),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
child: Text(
|
||||
'Your shift has been updated successfully.',
|
||||
t.client_view_orders.order_edit_sheet.order_updated_message,
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body1r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
@@ -1685,7 +1688,7 @@ class OrderEditSheetState extends State<OrderEditSheet> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
child: UiButton.secondary(
|
||||
text: 'Back to Orders',
|
||||
text: t.client_view_orders.order_edit_sheet.back_to_orders,
|
||||
fullWidth: true,
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: UiColors.white,
|
||||
|
||||
Reference in New Issue
Block a user