176 lines
5.3 KiB
Dart
176 lines
5.3 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:pshared/models/payment/methods/data.dart';
|
|
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/recipient/methods_cache.dart';
|
|
import 'package:pshared/provider/recipient/provider.dart';
|
|
|
|
import 'package:pweb/pages/address_book/form/view.dart';
|
|
import 'package:pweb/services/posthog.dart';
|
|
import 'package:pweb/utils/error/snackbar.dart';
|
|
import 'package:pweb/utils/payment/label.dart';
|
|
import 'package:pweb/utils/snackbar.dart';
|
|
|
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
|
|
|
|
|
class AddressBookRecipientForm extends StatefulWidget {
|
|
final Recipient? recipient;
|
|
final ValueChanged<Recipient?>? onSaved;
|
|
|
|
const AddressBookRecipientForm({super.key, this.recipient, this.onSaved});
|
|
|
|
@override
|
|
State<AddressBookRecipientForm> createState() => _AddressBookRecipientFormState();
|
|
}
|
|
|
|
class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
late TextEditingController _nameCtrl;
|
|
late TextEditingController _emailCtrl;
|
|
RecipientType _type = RecipientType.internal;
|
|
RecipientStatus _status = RecipientStatus.ready;
|
|
final MethodMap _methods = {};
|
|
late RecipientMethodsCacheProvider _methodsCacheProvider;
|
|
bool _hasInitializedMethods = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final r = widget.recipient;
|
|
_nameCtrl = TextEditingController(text: r?.name ?? '');
|
|
_emailCtrl = TextEditingController(text: r?.email ?? '');
|
|
_type = r?.type ?? RecipientType.internal;
|
|
_status = r?.status ?? RecipientStatus.ready;
|
|
_methodsCacheProvider = context.read<RecipientMethodsCacheProvider>()
|
|
..addListener(_onProviderChanged);
|
|
if (r != null) {
|
|
_methodsCacheProvider.refreshRecipient(r.id);
|
|
_syncMethodsFromCache();
|
|
}
|
|
}
|
|
|
|
Future<Recipient?> _doSave() async {
|
|
final recipients = context.read<RecipientsProvider>();
|
|
final recipient = widget.recipient == null
|
|
? await recipients.create(
|
|
name: _nameCtrl.text,
|
|
email: _emailCtrl.text,
|
|
)
|
|
: widget.recipient!;
|
|
recipients.setCurrentObject(recipient.id);
|
|
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;
|
|
}
|
|
|
|
Future<void> _save() async {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
|
|
if (!_formKey.currentState!.validate()) {
|
|
notifyUser(context, l10n.recipientFormValidationError);
|
|
return;
|
|
}
|
|
|
|
if (_methods.isEmpty) {
|
|
notifyUser(context, l10n.recipientFormRule);
|
|
return;
|
|
}
|
|
|
|
unawaited(PosthogService.recipientAddCompleted(
|
|
_type,
|
|
_status,
|
|
_methods.keys.toSet(),
|
|
));
|
|
final recipient = await executeActionWithNotification(
|
|
context: context,
|
|
action: _doSave,
|
|
errorMessage: l10n.errorSaveRecipient,
|
|
successMessage: l10n.recipientSavedSuccessfully,
|
|
);
|
|
|
|
|
|
widget.onSaved?.call(recipient);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_methodsCacheProvider.removeListener(_onProviderChanged);
|
|
super.dispose();
|
|
}
|
|
|
|
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(
|
|
formKey: _formKey,
|
|
nameCtrl: _nameCtrl,
|
|
emailCtrl: _emailCtrl,
|
|
type: _type,
|
|
status: _status,
|
|
methods: _methods,
|
|
onTypeChanged: (t) => setState(() => _type = t),
|
|
onStatusChanged: (s) => setState(() => _status = s),
|
|
onMethodsChanged: (type, data) {
|
|
setState(() {
|
|
if (data != null) {
|
|
_methods[type] = data;
|
|
} else {
|
|
_methods.remove(type);
|
|
}
|
|
});
|
|
},
|
|
onSave: _save,
|
|
isEditing: widget.recipient != null,
|
|
onBack: () {
|
|
widget.onSaved?.call(null);
|
|
},
|
|
);
|
|
}
|