Fixed payment method deletion in recipient settings with better flow

This commit is contained in:
Arseni
2026-01-23 16:28:09 +03:00
parent bdb84ac6ac
commit 3765780a4d
7 changed files with 265 additions and 82 deletions

View File

@@ -5,6 +5,9 @@ import 'package:pshared/models/payment/type.dart';
import 'package:pweb/pages/payment_methods/form.dart';
import 'package:pweb/pages/payment_methods/icon.dart';
import 'package:pweb/widgets/dialogs/confirmation_dialog.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class AddressBookPaymentMethodTile extends StatefulWidget {
@@ -35,6 +38,19 @@ class AddressBookPaymentMethodTile extends StatefulWidget {
}
class _AddressBookPaymentMethodTileState extends State<AddressBookPaymentMethodTile> {
Future<void> _confirmDelete() async {
final l10n = AppLocalizations.of(context)!;
final confirmed = await showConfirmationDialog(
context: context,
title: l10n.delete,
message: l10n.deletePaymentConfirmation,
confirmLabel: l10n.delete,
);
if (confirmed) {
widget.onChanged(null);
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@@ -67,9 +83,7 @@ class _AddressBookPaymentMethodTileState extends State<AddressBookPaymentMethodT
if (isAdded)
IconButton(
icon: Icon(Icons.delete, color: theme.colorScheme.error),
onPressed: () {
widget.onChanged(null);
},
onPressed: _confirmDelete,
),
Icon(
isAdded ? Icons.check_circle : Icons.add_circle_outline,

View File

@@ -2,8 +2,6 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:provider/provider.dart';
import 'package:pshared/models/payment/methods/data.dart';
@@ -11,8 +9,7 @@ import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/models/recipient/status.dart';
import 'package:pshared/models/recipient/type.dart';
import 'package:pshared/provider/organizations.dart';
import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pshared/provider/recipient/methods_cache.dart';
import 'package:pshared/provider/recipient/provider.dart';
import 'package:pweb/pages/address_book/form/view.dart';
@@ -41,27 +38,8 @@ class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
RecipientType _type = RecipientType.internal;
RecipientStatus _status = RecipientStatus.ready;
final MethodMap _methods = {};
late PaymentMethodsProvider _methodsProvider;
Future<void> _loadMethods() async {
_methodsProvider = PaymentMethodsProvider()..addListener(_onProviderChanged);
await _methodsProvider.loadMethods(
context.read<OrganizationsProvider>(),
widget.recipient?.id,
);
for (final m in _methodsProvider.methods) {
_methods[m.type] = switch (m.type) {
PaymentType.card => m.cardData,
PaymentType.iban => m.ibanData,
PaymentType.wallet => m.walletData,
PaymentType.bankAccount => m.bankAccountData,
PaymentType.externalChain => m.cryptoAddressData,
//TODO: support new payment methods
_ => throw UnimplementedError('Payment method ${m.type} is not supported yet'),
};
}
}
late RecipientMethodsCacheProvider _methodsCacheProvider;
bool _hasInitializedMethods = false;
@override
void initState() {
@@ -71,12 +49,16 @@ class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
_emailCtrl = TextEditingController(text: r?.email ?? '');
_type = r?.type ?? RecipientType.internal;
_status = r?.status ?? RecipientStatus.ready;
_loadMethods();
_methodsCacheProvider = context.read<RecipientMethodsCacheProvider>()
..addListener(_onProviderChanged);
if (r != null) {
_methodsCacheProvider.refreshRecipient(r.id);
_syncMethodsFromCache();
}
}
Future<Recipient?> _doSave() async {
final recipients = context.read<RecipientsProvider>();
final methods = PaymentMethodsProvider();
final recipient = widget.recipient == null
? await recipients.create(
name: _nameCtrl.text,
@@ -84,25 +66,22 @@ class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
)
: widget.recipient!;
recipients.setCurrentObject(recipient.id);
//TODO : redesign work with recipients / payment methods
await methods.loadMethods(context.read<OrganizationsProvider>(), recipient.id);
for (final type in _methods.keys) {
final data = _methods[type]!;
final exising = methods.methods.firstWhereOrNull((m) => m.type == type);
if (exising != null) {
await methods.updateMethod(exising.copyWith(data: data));
} else {
await methods.create(
reacipientRef: recipient.id,
name: getPaymentTypeLabel(context, type),
data: data,
);
}
final methods = <PaymentType, PaymentMethodData>{};
final names = <PaymentType, String>{};
for (final entry in _methods.entries) {
final data = entry.value;
if (data == null) continue;
methods[entry.key] = data;
names[entry.key] = getPaymentTypeLabel(context, entry.key);
}
await _methodsCacheProvider.syncRecipientMethods(
recipientId: recipient.id,
methods: methods,
names: names,
);
return recipient;
}
//TODO: Change when registration is ready
Future<void> _save() async {
final l10n = AppLocalizations.of(context)!;
@@ -134,12 +113,39 @@ class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
@override
void dispose() {
_methodsProvider.removeListener(_onProviderChanged);
_methodsProvider.dispose();
_methodsCacheProvider.removeListener(_onProviderChanged);
super.dispose();
}
void _onProviderChanged() => setState(() {});
void _onProviderChanged() => _syncMethodsFromCache();
void _syncMethodsFromCache() {
final recipient = widget.recipient;
if (recipient == null || _hasInitializedMethods) return;
if (!_methodsCacheProvider.hasMethodsFor(recipient.id)) return;
final list = _methodsCacheProvider.methodsForRecipient(recipient.id);
if (list.isEmpty) {
_hasInitializedMethods = true;
return;
}
setState(() {
_methods
..clear()
..addEntries(list.map((m) {
final data = switch (m.type) {
PaymentType.card => m.cardData,
PaymentType.iban => m.ibanData,
PaymentType.wallet => m.walletData,
PaymentType.bankAccount => m.bankAccountData,
PaymentType.externalChain => m.cryptoAddressData,
//TODO: support new payment methods
_ => throw UnimplementedError('Payment method ${m.type} is not supported yet'),
};
return MapEntry(m.type, data);
}));
_hasInitializedMethods = true;
});
}
@override
Widget build(BuildContext context) => FormView(