Files
sendico/frontend/pweb/lib/pages/dashboard/buttons/balance/add/dialog.dart
2026-01-23 02:48:10 +01:00

186 lines
6.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:provider/provider.dart';
import 'package:pshared/models/currency.dart';
import 'package:pshared/models/describable.dart';
import 'package:pshared/models/payment/chain_network.dart';
import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/wallet/chain_asset.dart';
import 'package:pshared/provider/accounts/employees.dart';
import 'package:pshared/provider/ledger.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pshared/utils/currency.dart';
import 'package:pweb/pages/dashboard/buttons/balance/add/form.dart';
import 'package:pweb/pages/dashboard/buttons/balance/add/constants.dart';
import 'package:pweb/pages/dashboard/buttons/balance/add/cancel.dart';
import 'package:pweb/pages/dashboard/buttons/balance/add/submit.dart';
import 'package:pweb/utils/error/snackbar.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
Future<void> showAddBalanceDialog(BuildContext context) => showDialog<void>(
context: context,
builder: (dialogContext) => const AddBalanceDialog(),
);
class AddBalanceDialog extends StatefulWidget {
const AddBalanceDialog({super.key});
@override
State<AddBalanceDialog> createState() => _AddBalanceDialogState();
}
class _AddBalanceDialogState extends State<AddBalanceDialog> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _descriptionController = TextEditingController();
PaymentType _assetType = PaymentType.managedWallet;
String? _ownerRef;
Currency _managedCurrency = managedCurrencyDefault;
ChainNetwork _network = managedNetworkDefault;
Currency _ledgerCurrency = ledgerCurrencyDefault;
@override
void dispose() {
_nameController.dispose();
_descriptionController.dispose();
super.dispose();
}
void _setAssetType(PaymentType? value) {
if (value == null) return;
setState(() => _assetType = value);
}
void _setOwnerRef(String? value) => setState(() => _ownerRef = value);
void _setManagedCurrency(Currency? value) {
if (value == null) return;
setState(() => _managedCurrency = value);
}
void _setNetwork(ChainNetwork? value) {
if (value == null) return;
setState(() => _network = value);
}
void _setLedgerCurrency(Currency? value) {
if (value == null) return;
setState(() => _ledgerCurrency = value);
}
Future<void> _submit() async {
final form = _formKey.currentState;
if (form == null || !form.validate()) return;
final l10n = AppLocalizations.of(context)!;
final name = _nameController.text.trim();
final description = _descriptionController.text.trim();
final employees = context.read<EmployeesProvider>().employees;
final effectiveOwnerRef = employees.any((employee) => employee.id == _ownerRef)
? _ownerRef
: null;
final isOrgWallet = effectiveOwnerRef == null;
final owner = isOrgWallet
? null
: employees.firstWhereOrNull((employee) => employee.id == effectiveOwnerRef);
final errorMessage = _assetType == PaymentType.managedWallet
? l10n.errorCreateManagedWallet
: l10n.errorCreateLedgerAccount;
final result = await executeActionWithNotification<bool>(
context: context,
errorMessage: errorMessage,
action: () async {
if (_assetType == PaymentType.managedWallet) {
await context.read<WalletsProvider>().create(
describable: newDescribable(name: name, description: description),
asset: ChainAsset(chain: _network, tokenSymbol: currencyCodeToString(_managedCurrency)),
ownerRef: owner?.id,
);
} else {
await context.read<LedgerAccountsProvider>().create(
describable: newDescribable(name: name, description: description),
currency: _ledgerCurrency,
ownerRef: owner?.id,
);
}
return true;
},
);
if (result == true && mounted) {
Navigator.of(context).pop();
}
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final screenWidth = MediaQuery.of(context).size.width;
final maxWidth = (screenWidth - 48).clamp(0.0, double.infinity);
final dialogWidth = maxWidth >= 360.0 ? (maxWidth > 520.0 ? 520.0 : maxWidth) : maxWidth;
final employeesProvider = context.watch<EmployeesProvider>();
final employees = employeesProvider.employees;
final isSaving = context.watch<WalletsProvider>().isLoading ||
context.watch<LedgerAccountsProvider>().isLoading;
final ownerItems = <DropdownMenuItem<String?>>[
DropdownMenuItem(
value: null,
child: Text(l10n.organizationOwned),
),
...employees.map((employee) => DropdownMenuItem(
value: employee.id,
child: Text(employee.fullName.isNotEmpty ? employee.fullName : employee.login),
)),
];
final resolvedOwnerRef = ownerItems.any((item) => item.value == _ownerRef) ? _ownerRef : null;
return AlertDialog(
title: Text(l10n.actionAddNew),
content: SizedBox(
width: dialogWidth,
child: AddBalanceForm(
formKey: _formKey,
assetType: _assetType,
isSaving: isSaving,
ownerItems: ownerItems,
ownerValue: resolvedOwnerRef,
onAssetTypeChanged: _setAssetType,
onOwnerChanged: _setOwnerRef,
nameController: _nameController,
descriptionController: _descriptionController,
managedCurrency: _managedCurrency,
network: _network,
ledgerCurrency: _ledgerCurrency,
onManagedCurrencyChanged: _setManagedCurrency,
onNetworkChanged: _setNetwork,
onLedgerCurrencyChanged: _setLedgerCurrency,
showEmployeesLoading: employeesProvider.isLoading,
),
),
actions: [
DialogCancelButton(
label: l10n.cancel,
isSaving: isSaving,
onCancel: () => Navigator.of(context).pop(),
),
DialogSubmitButton(
label: l10n.add,
isSaving: isSaving,
onSubmit: _submit,
),
],
);
}
}