feat: complete client reports and hub management UI, comment out export buttons
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:krow_core/core.dart';
|
||||||
|
import '../repositories/client_create_order_repository_interface.dart';
|
||||||
|
|
||||||
|
/// Arguments for the ReorderUseCase.
|
||||||
|
class ReorderArguments {
|
||||||
|
const ReorderArguments({
|
||||||
|
required this.previousOrderId,
|
||||||
|
required this.newDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String previousOrderId;
|
||||||
|
final DateTime newDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use case for reordering an existing staffing order.
|
||||||
|
class ReorderUseCase implements UseCase<Future<void>, ReorderArguments> {
|
||||||
|
const ReorderUseCase(this._repository);
|
||||||
|
|
||||||
|
final ClientCreateOrderRepositoryInterface _repository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> call(ReorderArguments params) {
|
||||||
|
return _repository.reorder(params.previousOrderId, params.newDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
|
||||||
|
import '../repositories/hub_repository_interface.dart';
|
||||||
|
import '../../domain/arguments/create_hub_arguments.dart';
|
||||||
|
|
||||||
|
/// Arguments for the UpdateHubUseCase.
|
||||||
|
class UpdateHubArguments {
|
||||||
|
const UpdateHubArguments({
|
||||||
|
required this.id,
|
||||||
|
this.name,
|
||||||
|
this.address,
|
||||||
|
this.placeId,
|
||||||
|
this.latitude,
|
||||||
|
this.longitude,
|
||||||
|
this.city,
|
||||||
|
this.state,
|
||||||
|
this.street,
|
||||||
|
this.country,
|
||||||
|
this.zipCode,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String? name;
|
||||||
|
final String? address;
|
||||||
|
final String? placeId;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
|
final String? city;
|
||||||
|
final String? state;
|
||||||
|
final String? street;
|
||||||
|
final String? country;
|
||||||
|
final String? zipCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use case for updating an existing hub.
|
||||||
|
class UpdateHubUseCase implements UseCase<Future<Hub>, UpdateHubArguments> {
|
||||||
|
UpdateHubUseCase(this.repository);
|
||||||
|
|
||||||
|
final HubRepositoryInterface repository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Hub> call(UpdateHubArguments params) {
|
||||||
|
return repository.updateHub(
|
||||||
|
id: params.id,
|
||||||
|
name: params.name,
|
||||||
|
address: params.address,
|
||||||
|
placeId: params.placeId,
|
||||||
|
latitude: params.latitude,
|
||||||
|
longitude: params.longitude,
|
||||||
|
city: params.city,
|
||||||
|
state: params.state,
|
||||||
|
street: params.street,
|
||||||
|
country: params.country,
|
||||||
|
zipCode: params.zipCode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
import 'package:design_system/design_system.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_modular/flutter_modular.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
import '../blocs/client_hubs_bloc.dart';
|
||||||
|
import '../blocs/client_hubs_event.dart';
|
||||||
|
import '../widgets/hub_form_dialog.dart';
|
||||||
|
|
||||||
|
class HubDetailsPage extends StatelessWidget {
|
||||||
|
const HubDetailsPage({
|
||||||
|
required this.hub,
|
||||||
|
required this.bloc,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Hub hub;
|
||||||
|
final ClientHubsBloc bloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider<ClientHubsBloc>.value(
|
||||||
|
value: bloc,
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(hub.name),
|
||||||
|
backgroundColor: UiColors.foreground,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(UiIcons.arrowLeft, color: UiColors.white),
|
||||||
|
onPressed: () => Modular.to.pop(),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(UiIcons.edit, color: UiColors.white),
|
||||||
|
onPressed: () => _showEditDialog(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: UiColors.bgMenu,
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(UiConstants.space5),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildDetailItem(
|
||||||
|
label: 'Name',
|
||||||
|
value: hub.name,
|
||||||
|
icon: UiIcons.home,
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space4),
|
||||||
|
_buildDetailItem(
|
||||||
|
label: 'Address',
|
||||||
|
value: hub.address,
|
||||||
|
icon: UiIcons.mapPin,
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space4),
|
||||||
|
_buildDetailItem(
|
||||||
|
label: 'NFC Tag',
|
||||||
|
value: hub.nfcTagId ?? 'Not Assigned',
|
||||||
|
icon: UiIcons.nfc,
|
||||||
|
isHighlight: hub.nfcTagId != null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDetailItem({
|
||||||
|
required String label,
|
||||||
|
required String value,
|
||||||
|
required IconData icon,
|
||||||
|
bool isHighlight = false,
|
||||||
|
}) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(UiConstants.space4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: UiColors.white,
|
||||||
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: UiColors.popupShadow,
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(UiConstants.space3),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isHighlight ? UiColors.tagInProgress : UiColors.bgInput,
|
||||||
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
icon,
|
||||||
|
color: isHighlight ? UiColors.iconSuccess : UiColors.iconPrimary,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: UiConstants.space4),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: UiTypography.footnote1r.textSecondary,
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space1),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: UiTypography.body1m.textPrimary,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showEditDialog(BuildContext context) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (_) => HubFormDialog(
|
||||||
|
hub: hub,
|
||||||
|
onSave: (name, address, {placeId, latitude, longitude, city, state, street, country, zipCode}) {
|
||||||
|
bloc.add(
|
||||||
|
ClientHubsUpdateRequested(
|
||||||
|
id: hub.id,
|
||||||
|
name: name,
|
||||||
|
address: address,
|
||||||
|
placeId: placeId,
|
||||||
|
latitude: latitude,
|
||||||
|
longitude: longitude,
|
||||||
|
city: city,
|
||||||
|
state: state,
|
||||||
|
street: street,
|
||||||
|
country: country,
|
||||||
|
zipCode: zipCode,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Navigator.of(context).pop(); // Close dialog
|
||||||
|
Navigator.of(context).pop(); // Go back to list to refresh
|
||||||
|
},
|
||||||
|
onCancel: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
import 'package:design_system/design_system.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:core_localization/core_localization.dart';
|
||||||
|
import 'package:google_places_flutter/model/prediction.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
|
||||||
|
import 'hub_address_autocomplete.dart';
|
||||||
|
|
||||||
|
/// A dialog for adding or editing a hub.
|
||||||
|
class HubFormDialog extends StatefulWidget {
|
||||||
|
|
||||||
|
/// Creates a [HubFormDialog].
|
||||||
|
const HubFormDialog({
|
||||||
|
required this.onSave,
|
||||||
|
required this.onCancel,
|
||||||
|
this.hub,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The hub to edit. If null, a new hub is created.
|
||||||
|
final Hub? hub;
|
||||||
|
|
||||||
|
/// Callback when the "Save" button is pressed.
|
||||||
|
final void Function(
|
||||||
|
String name,
|
||||||
|
String address, {
|
||||||
|
String? placeId,
|
||||||
|
double? latitude,
|
||||||
|
double? longitude,
|
||||||
|
}) onSave;
|
||||||
|
|
||||||
|
/// Callback when the dialog is cancelled.
|
||||||
|
final VoidCallback onCancel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HubFormDialog> createState() => _HubFormDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HubFormDialogState extends State<HubFormDialog> {
|
||||||
|
late final TextEditingController _nameController;
|
||||||
|
late final TextEditingController _addressController;
|
||||||
|
late final FocusNode _addressFocusNode;
|
||||||
|
Prediction? _selectedPrediction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_nameController = TextEditingController(text: widget.hub?.name);
|
||||||
|
_addressController = TextEditingController(text: widget.hub?.address);
|
||||||
|
_addressFocusNode = FocusNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_nameController.dispose();
|
||||||
|
_addressController.dispose();
|
||||||
|
_addressFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final bool isEditing = widget.hub != null;
|
||||||
|
final String title = isEditing
|
||||||
|
? 'Edit Hub' // TODO: localize
|
||||||
|
: t.client_hubs.add_hub_dialog.title;
|
||||||
|
|
||||||
|
final String buttonText = isEditing
|
||||||
|
? 'Save Changes' // TODO: localize
|
||||||
|
: t.client_hubs.add_hub_dialog.create_button;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
color: UiColors.bgOverlay,
|
||||||
|
child: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.9,
|
||||||
|
padding: const EdgeInsets.all(UiConstants.space5),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: UiColors.bgPopup,
|
||||||
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
|
boxShadow: const <BoxShadow>[
|
||||||
|
BoxShadow(color: UiColors.popupShadow, blurRadius: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: UiTypography.headline3m.textPrimary,
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space5),
|
||||||
|
_buildFieldLabel(t.client_hubs.add_hub_dialog.name_label),
|
||||||
|
TextFormField(
|
||||||
|
controller: _nameController,
|
||||||
|
style: UiTypography.body1r.textPrimary,
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value == null || value.trim().isEmpty) {
|
||||||
|
return 'Name is required';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
decoration: _buildInputDecoration(
|
||||||
|
t.client_hubs.add_hub_dialog.name_hint,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space4),
|
||||||
|
_buildFieldLabel(t.client_hubs.add_hub_dialog.address_label),
|
||||||
|
HubAddressAutocomplete(
|
||||||
|
controller: _addressController,
|
||||||
|
hintText: t.client_hubs.add_hub_dialog.address_hint,
|
||||||
|
focusNode: _addressFocusNode,
|
||||||
|
onSelected: (Prediction prediction) {
|
||||||
|
_selectedPrediction = prediction;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: UiConstants.space8),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: UiButton.secondary(
|
||||||
|
onPressed: widget.onCancel,
|
||||||
|
text: t.common.cancel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: UiConstants.space3),
|
||||||
|
Expanded(
|
||||||
|
child: UiButton.primary(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
if (_addressController.text.trim().isEmpty) {
|
||||||
|
UiSnackbar.show(context, message: 'Address is required', type: UiSnackbarType.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.onSave(
|
||||||
|
_nameController.text,
|
||||||
|
_addressController.text,
|
||||||
|
placeId: _selectedPrediction?.placeId,
|
||||||
|
latitude: double.tryParse(
|
||||||
|
_selectedPrediction?.lat ?? '',
|
||||||
|
),
|
||||||
|
longitude: double.tryParse(
|
||||||
|
_selectedPrediction?.lng ?? '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text: buttonText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFieldLabel(String label) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: UiConstants.space2),
|
||||||
|
child: Text(label, style: UiTypography.body2m.textPrimary),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDecoration _buildInputDecoration(String hint) {
|
||||||
|
return InputDecoration(
|
||||||
|
hintText: hint,
|
||||||
|
hintStyle: UiTypography.body2r.textPlaceholder,
|
||||||
|
filled: true,
|
||||||
|
fillColor: UiColors.input,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: UiConstants.space4,
|
||||||
|
vertical: 14,
|
||||||
|
),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
|
borderSide: const BorderSide(color: UiColors.border),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
|
borderSide: const BorderSide(color: UiColors.border),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
|
borderSide: const BorderSide(color: UiColors.ring, width: 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -120,6 +120,7 @@ class _CoverageReportPageState extends State<CoverageReportPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Export button
|
// Export button
|
||||||
|
/*
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -158,6 +159,7 @@ class _CoverageReportPageState extends State<CoverageReportPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class _DailyOpsReportPageState extends State<DailyOpsReportPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -176,6 +177,7 @@ class _DailyOpsReportPageState extends State<DailyOpsReportPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ class _NoShowReportPageState extends State<NoShowReportPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Export button
|
// Export button
|
||||||
|
/*
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -137,6 +138,7 @@ class _NoShowReportPageState extends State<NoShowReportPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ class _PerformanceReportPageState extends State<PerformanceReportPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Export
|
// Export
|
||||||
|
/*
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -217,6 +218,7 @@ class _PerformanceReportPageState extends State<PerformanceReportPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ class _SpendReportPageState extends State<SpendReportPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -154,6 +155,7 @@ class _SpendReportPageState extends State<SpendReportPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import 'package:core_localization/core_localization.dart';
|
||||||
|
import 'package:design_system/design_system.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_modular/flutter_modular.dart';
|
||||||
|
import 'package:krow_core/core.dart';
|
||||||
|
import '../../blocs/client_settings_bloc.dart';
|
||||||
|
|
||||||
|
/// A widget that displays the log out button.
|
||||||
|
class SettingsLogout extends StatelessWidget {
|
||||||
|
/// Creates a [SettingsLogout].
|
||||||
|
const SettingsLogout({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final TranslationsClientSettingsProfileEn labels =
|
||||||
|
t.client_settings.profile;
|
||||||
|
|
||||||
|
return SliverPadding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: BlocBuilder<ClientSettingsBloc, ClientSettingsState>(
|
||||||
|
builder: (BuildContext context, ClientSettingsState state) {
|
||||||
|
return UiButton.primary(
|
||||||
|
text: labels.log_out,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: UiColors.white,
|
||||||
|
foregroundColor: UiColors.textPrimary,
|
||||||
|
side: const BorderSide(color: UiColors.textPrimary),
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
onPressed: state is ClientSettingsLoading
|
||||||
|
? null
|
||||||
|
: () => _showSignOutDialog(context),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the sign-out button click event.
|
||||||
|
void _onSignoutClicked(BuildContext context) {
|
||||||
|
ReadContext(
|
||||||
|
context,
|
||||||
|
).read<ClientSettingsBloc>().add(const ClientSettingsSignOutRequested());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows a confirmation dialog for signing out.
|
||||||
|
Future<void> _showSignOutDialog(BuildContext context) {
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) => AlertDialog(
|
||||||
|
backgroundColor: UiColors.bgPopup,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusLg),
|
||||||
|
title: Text(
|
||||||
|
t.client_settings.profile.log_out,
|
||||||
|
style: UiTypography.headline3m.textPrimary,
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
t.client_settings.profile.log_out_confirmation,
|
||||||
|
style: UiTypography.body2r.textSecondary,
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
// Log out button
|
||||||
|
UiButton.primary(
|
||||||
|
text: t.client_settings.profile.log_out,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: UiColors.white,
|
||||||
|
foregroundColor: UiColors.textPrimary,
|
||||||
|
side: const BorderSide(color: UiColors.textPrimary),
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
onPressed: () => _onSignoutClicked(context),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Cancel button
|
||||||
|
UiButton.secondary(
|
||||||
|
text: t.common.cancel,
|
||||||
|
onPressed: () => Modular.to.pop(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,4 +3,3 @@ export 'src/presentation/pages/get_started_page.dart';
|
|||||||
export 'src/presentation/pages/phone_verification_page.dart';
|
export 'src/presentation/pages/phone_verification_page.dart';
|
||||||
export 'src/presentation/pages/profile_setup_page.dart';
|
export 'src/presentation/pages/profile_setup_page.dart';
|
||||||
export 'src/staff_authentication_module.dart';
|
export 'src/staff_authentication_module.dart';
|
||||||
export 'src/domain/repositories/auth_repository_interface.dart';
|
|
||||||
|
|||||||
Reference in New Issue
Block a user