UI fields for cost center

This commit is contained in:
2026-02-25 13:03:04 +05:30
parent 5eea0d38cc
commit 714702015c
14 changed files with 188 additions and 8 deletions

View File

@@ -252,6 +252,8 @@
"location_hint": "e.g., Downtown Restaurant",
"address_label": "Address",
"address_hint": "Full address",
"cost_center_label": "Cost Center",
"cost_center_hint": "eg: 1001, 1002",
"create_button": "Create Hub"
},
"edit_hub": {
@@ -261,6 +263,8 @@
"name_hint": "e.g., Main Kitchen, Front Desk",
"address_label": "Address",
"address_hint": "Full address",
"cost_center_label": "Cost Center",
"cost_center_hint": "eg: 1001, 1002",
"save_button": "Save Changes",
"success": "Hub updated successfully!"
},
@@ -270,6 +274,8 @@
"address_label": "Address",
"nfc_label": "NFC Tag",
"nfc_not_assigned": "Not Assigned",
"cost_center_label": "Cost Center",
"cost_center_none": "Not Assigned",
"edit_button": "Edit Hub"
},
"nfc_dialog": {

View File

@@ -252,6 +252,8 @@
"location_hint": "ej., Restaurante Centro",
"address_label": "Direcci\u00f3n",
"address_hint": "Direcci\u00f3n completa",
"cost_center_label": "Centro de Costos",
"cost_center_hint": "ej: 1001, 1002",
"create_button": "Crear Hub"
},
"nfc_dialog": {
@@ -276,6 +278,8 @@
"name_hint": "Ingresar nombre del hub",
"address_label": "Direcci\u00f3n",
"address_hint": "Ingresar direcci\u00f3n",
"cost_center_label": "Centro de Costos",
"cost_center_hint": "ej: 1001, 1002",
"save_button": "Guardar Cambios",
"success": "\u00a1Hub actualizado exitosamente!"
},
@@ -285,7 +289,9 @@
"name_label": "Nombre del Hub",
"address_label": "Direcci\u00f3n",
"nfc_label": "Etiqueta NFC",
"nfc_not_assigned": "No asignada"
"nfc_not_assigned": "No asignada",
"cost_center_label": "Centro de Costos",
"cost_center_none": "No asignado"
}
},
"client_create_order": {

View File

@@ -14,7 +14,6 @@ enum HubStatus {
/// Represents a branch location or operational unit within a [Business].
class Hub extends Equatable {
const Hub({
required this.id,
required this.businessId,
@@ -22,6 +21,7 @@ class Hub extends Equatable {
required this.address,
this.nfcTagId,
required this.status,
this.costCenter,
});
/// Unique identifier.
final String id;
@@ -41,6 +41,9 @@ class Hub extends Equatable {
/// Operational status.
final HubStatus status;
/// Assigned cost center for this hub.
final String? costCenter;
@override
List<Object?> get props => <Object?>[id, businessId, name, address, nfcTagId, status];
List<Object?> get props => <Object?>[id, businessId, name, address, nfcTagId, status, costCenter];
}

View File

@@ -36,6 +36,7 @@ class HubRepositoryImpl implements HubRepositoryInterface {
String? street,
String? country,
String? zipCode,
String? costCenter,
}) async {
final String businessId = await _service.getBusinessId();
return _connectorRepository.createHub(
@@ -79,6 +80,7 @@ class HubRepositoryImpl implements HubRepositoryInterface {
String? street,
String? country,
String? zipCode,
String? costCenter,
}) async {
final String businessId = await _service.getBusinessId();
return _connectorRepository.updateHub(

View File

@@ -19,6 +19,7 @@ class CreateHubArguments extends UseCaseArgument {
this.street,
this.country,
this.zipCode,
this.costCenter,
});
/// The name of the hub.
final String name;
@@ -34,6 +35,9 @@ class CreateHubArguments extends UseCaseArgument {
final String? street;
final String? country;
final String? zipCode;
/// The cost center of the hub.
final String? costCenter;
@override
List<Object?> get props => <Object?>[
@@ -47,5 +51,6 @@ class CreateHubArguments extends UseCaseArgument {
street,
country,
zipCode,
costCenter,
];
}

View File

@@ -26,6 +26,7 @@ abstract interface class HubRepositoryInterface {
String? street,
String? country,
String? zipCode,
String? costCenter,
});
/// Deletes a hub by its [id].
@@ -51,5 +52,6 @@ abstract interface class HubRepositoryInterface {
String? street,
String? country,
String? zipCode,
String? costCenter,
});
}

View File

@@ -16,7 +16,9 @@ class UpdateHubArguments extends UseCaseArgument {
this.state,
this.street,
this.country,
this.country,
this.zipCode,
this.costCenter,
});
final String id;
@@ -30,6 +32,7 @@ class UpdateHubArguments extends UseCaseArgument {
final String? street;
final String? country;
final String? zipCode;
final String? costCenter;
@override
List<Object?> get props => <Object?>[
@@ -44,6 +47,7 @@ class UpdateHubArguments extends UseCaseArgument {
street,
country,
zipCode,
costCenter,
];
}
@@ -67,6 +71,7 @@ class UpdateHubUseCase implements UseCase<UpdateHubArguments, Hub> {
street: params.street,
country: params.country,
zipCode: params.zipCode,
costCenter: params.costCenter,
);
}
}

View File

@@ -106,6 +106,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
street: event.street,
country: event.country,
zipCode: event.zipCode,
costCenter: event.costCenter,
),
);
final List<Hub> hubs = await _getHubsUseCase();
@@ -147,6 +148,7 @@ class ClientHubsBloc extends Bloc<ClientHubsEvent, ClientHubsState>
street: event.street,
country: event.country,
zipCode: event.zipCode,
costCenter: event.costCenter,
),
);
final List<Hub> hubs = await _getHubsUseCase();

View File

@@ -28,6 +28,7 @@ class ClientHubsAddRequested extends ClientHubsEvent {
this.street,
this.country,
this.zipCode,
this.costCenter,
});
final String name;
final String address;
@@ -39,6 +40,7 @@ class ClientHubsAddRequested extends ClientHubsEvent {
final String? street;
final String? country;
final String? zipCode;
final String? costCenter;
@override
List<Object?> get props => <Object?>[
@@ -52,6 +54,7 @@ class ClientHubsAddRequested extends ClientHubsEvent {
street,
country,
zipCode,
costCenter,
];
}
@@ -69,6 +72,7 @@ class ClientHubsUpdateRequested extends ClientHubsEvent {
this.street,
this.country,
this.zipCode,
this.costCenter,
});
final String id;
@@ -82,6 +86,7 @@ class ClientHubsUpdateRequested extends ClientHubsEvent {
final String? street;
final String? country;
final String? zipCode;
final String? costCenter;
@override
List<Object?> get props => <Object?>[
@@ -96,6 +101,7 @@ class ClientHubsUpdateRequested extends ClientHubsEvent {
street,
country,
zipCode,
costCenter,
];
}

View File

@@ -32,6 +32,7 @@ class EditHubPage extends StatefulWidget {
class _EditHubPageState extends State<EditHubPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late final TextEditingController _nameController;
late final TextEditingController _costCenterController;
late final TextEditingController _addressController;
late final FocusNode _addressFocusNode;
Prediction? _selectedPrediction;
@@ -40,6 +41,7 @@ class _EditHubPageState extends State<EditHubPage> {
void initState() {
super.initState();
_nameController = TextEditingController(text: widget.hub.name);
_costCenterController = TextEditingController(text: widget.hub.costCenter);
_addressController = TextEditingController(text: widget.hub.address);
_addressFocusNode = FocusNode();
}
@@ -47,6 +49,7 @@ class _EditHubPageState extends State<EditHubPage> {
@override
void dispose() {
_nameController.dispose();
_costCenterController.dispose();
_addressController.dispose();
_addressFocusNode.dispose();
super.dispose();
@@ -72,6 +75,7 @@ class _EditHubPageState extends State<EditHubPage> {
placeId: _selectedPrediction?.placeId,
latitude: double.tryParse(_selectedPrediction?.lat ?? ''),
longitude: double.tryParse(_selectedPrediction?.lng ?? ''),
costCenter: _costCenterController.text.trim().isEmpty ? null : _costCenterController.text.trim(),
),
);
}
@@ -160,6 +164,19 @@ class _EditHubPageState extends State<EditHubPage> {
const SizedBox(height: UiConstants.space4),
// ── Cost Center field ────────────────────────────
_FieldLabel(t.client_hubs.edit_hub.cost_center_label),
TextFormField(
controller: _costCenterController,
style: UiTypography.body1r.textPrimary,
textInputAction: TextInputAction.next,
decoration: _inputDecoration(
t.client_hubs.edit_hub.cost_center_hint,
),
),
const SizedBox(height: UiConstants.space4),
// ── Address field ────────────────────────────────
_FieldLabel(t.client_hubs.edit_hub.address_label),
HubAddressAutocomplete(

View File

@@ -54,6 +54,14 @@ class HubDetailsPage extends StatelessWidget {
icon: UiIcons.home,
),
const SizedBox(height: UiConstants.space4),
_buildDetailItem(
label: t.client_hubs.hub_details.cost_center_label,
value: hub.costCenter?.isNotEmpty == true
? hub.costCenter!
: t.client_hubs.hub_details.cost_center_none,
icon: UiIcons.dollarSign, // or UiIcons.building, hash, etc.
),
const SizedBox(height: UiConstants.space4),
_buildDetailItem(
label: t.client_hubs.hub_details.address_label,
value: hub.address,

View File

@@ -21,6 +21,7 @@ class AddHubDialog extends StatefulWidget {
String? placeId,
double? latitude,
double? longitude,
String? costCenter,
}) onCreate;
/// Callback when the dialog is cancelled.
@@ -32,6 +33,7 @@ class AddHubDialog extends StatefulWidget {
class _AddHubDialogState extends State<AddHubDialog> {
late final TextEditingController _nameController;
late final TextEditingController _costCenterController;
late final TextEditingController _addressController;
late final FocusNode _addressFocusNode;
Prediction? _selectedPrediction;
@@ -40,6 +42,7 @@ class _AddHubDialogState extends State<AddHubDialog> {
void initState() {
super.initState();
_nameController = TextEditingController();
_costCenterController = TextEditingController();
_addressController = TextEditingController();
_addressFocusNode = FocusNode();
}
@@ -47,6 +50,7 @@ class _AddHubDialogState extends State<AddHubDialog> {
@override
void dispose() {
_nameController.dispose();
_costCenterController.dispose();
_addressController.dispose();
_addressFocusNode.dispose();
super.dispose();
@@ -96,6 +100,16 @@ class _AddHubDialogState extends State<AddHubDialog> {
),
),
const SizedBox(height: UiConstants.space4),
_buildFieldLabel(t.client_hubs.add_hub_dialog.cost_center_label),
TextFormField(
controller: _costCenterController,
style: UiTypography.body1r.textPrimary,
decoration: _buildInputDecoration(
t.client_hubs.add_hub_dialog.cost_center_hint,
),
textInputAction: TextInputAction.next,
),
const SizedBox(height: UiConstants.space4),
_buildFieldLabel(t.client_hubs.add_hub_dialog.address_label),
// Assuming HubAddressAutocomplete is a custom widget wrapper.
// If it doesn't expose a validator, we might need to modify it or manually check _addressController.
@@ -139,6 +153,7 @@ class _AddHubDialogState extends State<AddHubDialog> {
longitude: double.tryParse(
_selectedPrediction?.lng ?? '',
),
costCenter: _costCenterController.text.trim().isEmpty ? null : _costCenterController.text.trim(),
);
}
},

View File

@@ -27,6 +27,7 @@ class HubFormDialog extends StatefulWidget {
String? placeId,
double? latitude,
double? longitude,
String? costCenter,
}) onSave;
/// Callback when the dialog is cancelled.
@@ -38,6 +39,7 @@ class HubFormDialog extends StatefulWidget {
class _HubFormDialogState extends State<HubFormDialog> {
late final TextEditingController _nameController;
late final TextEditingController _costCenterController;
late final TextEditingController _addressController;
late final FocusNode _addressFocusNode;
Prediction? _selectedPrediction;
@@ -46,6 +48,7 @@ class _HubFormDialogState extends State<HubFormDialog> {
void initState() {
super.initState();
_nameController = TextEditingController(text: widget.hub?.name);
_costCenterController = TextEditingController(text: widget.hub?.costCenter);
_addressController = TextEditingController(text: widget.hub?.address);
_addressFocusNode = FocusNode();
}
@@ -53,6 +56,7 @@ class _HubFormDialogState extends State<HubFormDialog> {
@override
void dispose() {
_nameController.dispose();
_costCenterController.dispose();
_addressController.dispose();
_addressFocusNode.dispose();
super.dispose();
@@ -68,7 +72,7 @@ class _HubFormDialogState extends State<HubFormDialog> {
: t.client_hubs.add_hub_dialog.title;
final String buttonText = isEditing
? 'Save Changes' // TODO: localize
? t.client_hubs.edit_hub.save_button
: t.client_hubs.add_hub_dialog.create_button;
return Container(
@@ -111,6 +115,16 @@ class _HubFormDialogState extends State<HubFormDialog> {
),
),
const SizedBox(height: UiConstants.space4),
_buildFieldLabel(t.client_hubs.add_hub_dialog.cost_center_label),
TextFormField(
controller: _costCenterController,
style: UiTypography.body1r.textPrimary,
decoration: _buildInputDecoration(
t.client_hubs.add_hub_dialog.cost_center_hint,
),
textInputAction: TextInputAction.next,
),
const SizedBox(height: UiConstants.space4),
_buildFieldLabel(t.client_hubs.add_hub_dialog.address_label),
HubAddressAutocomplete(
controller: _addressController,
@@ -146,10 +160,11 @@ class _HubFormDialogState extends State<HubFormDialog> {
latitude: double.tryParse(
_selectedPrediction?.lat ?? '',
),
longitude: double.tryParse(
_selectedPrediction?.lng ?? '',
),
);
longitude: double.tryParse(
_selectedPrediction?.lng ?? '',
),
costCenter: _costCenterController.text.trim().isEmpty ? null : _costCenterController.text.trim(),
);
}
},
text: buttonText,