diff --git a/frontend/pshared/lib/provider/payment/flow.dart b/frontend/pshared/lib/provider/payment/flow.dart index 1f805523..f0760070 100644 --- a/frontend/pshared/lib/provider/payment/flow.dart +++ b/frontend/pshared/lib/provider/payment/flow.dart @@ -15,6 +15,7 @@ class PaymentFlowProvider extends ChangeNotifier { PaymentMethodData? _manualPaymentData; List _recipientMethods = []; Recipient? _recipient; + String? _selectedMethodId; PaymentFlowProvider({ required PaymentType initialType, @@ -25,9 +26,14 @@ class PaymentFlowProvider extends ChangeNotifier { PaymentType get selectedType => _selectedType; PaymentMethodData? get manualPaymentData => _manualPaymentData; Recipient? get recipient => _recipient; - PaymentMethod? get selectedMethod => hasRecipient - ? _recipientMethods.firstWhereOrNull((method) => method.type == _selectedType) - : null; + PaymentMethod? get selectedMethod { + if (!hasRecipient) return null; + if (_selectedMethodId != null) { + final byId = _recipientMethods.firstWhereOrNull((method) => method.id == _selectedMethodId); + if (byId != null) return byId; + } + return _preferredMethodForType(_selectedType, _recipientMethods); + } bool get hasRecipient => _recipient != null; @@ -42,6 +48,12 @@ class PaymentFlowProvider extends ChangeNotifier { ? List.unmodifiable(_recipientMethods) : const []; + List get methodsForSelectedType => hasRecipient + ? List.unmodifiable( + _recipientMethods.where((method) => method.type == _selectedType).toList(), + ) + : const []; + void update( RecipientsProvider recipientsProvider, PaymentMethodsProvider methodsProvider, @@ -63,12 +75,25 @@ class PaymentFlowProvider extends ChangeNotifier { } _selectedType = type; + if (hasRecipient) { + _selectedMethodId = _preferredMethodForType(type, _recipientMethods)?.id; + } if (resetManualData) { _manualPaymentData = null; } notifyListeners(); } + void selectMethod(PaymentMethod method) { + if (!hasRecipient) return; + if (_selectedMethodId == method.id && _selectedType == method.type) return; + _selectedMethodId = method.id; + if (_selectedType != method.type) { + _selectedType = method.type; + } + notifyListeners(); + } + void setManualPaymentData(PaymentMethodData? data) { _manualPaymentData = data; notifyListeners(); @@ -124,6 +149,12 @@ class PaymentFlowProvider extends ChangeNotifier { availableTypes: availableTypes, preferredType: preferredType, ); + final resolvedMethod = _resolveSelectedMethod( + recipient: recipient, + methods: methods, + selectedType: resolvedType, + selectedMethodId: _selectedMethodId, + ); var hasChanges = false; @@ -142,6 +173,11 @@ class PaymentFlowProvider extends ChangeNotifier { hasChanges = true; } + if ((resolvedMethod?.id ?? _selectedMethodId) != _selectedMethodId) { + _selectedMethodId = resolvedMethod?.id; + hasChanges = true; + } + if ((recipient != null || forceResetManualData) && _manualPaymentData != null) { _manualPaymentData = null; hasChanges = true; @@ -154,6 +190,28 @@ class PaymentFlowProvider extends ChangeNotifier { for (final method in methods) method.type: method.data, }; + PaymentMethod? _preferredMethodForType(PaymentType type, List methods) { + final forType = methods.where((method) => method.type == type).toList(); + if (forType.isEmpty) return null; + return forType.firstWhereOrNull((method) => method.isMain) ?? forType.first; + } + + PaymentMethod? _resolveSelectedMethod({ + required Recipient? recipient, + required List methods, + required PaymentType selectedType, + required String? selectedMethodId, + }) { + if (recipient == null) return null; + final forType = methods.where((method) => method.type == selectedType).toList(); + if (forType.isEmpty) return null; + if (selectedMethodId != null) { + final byId = forType.firstWhereOrNull((method) => method.id == selectedMethodId); + if (byId != null) return byId; + } + return _preferredMethodForType(selectedType, methods); + } + bool _hasSameMethods(List methods) { if (_recipientMethods.length != methods.length) return false; for (var i = 0; i < methods.length; i++) { diff --git a/frontend/pweb/lib/pages/payment_methods/widgets/payment_info_section.dart b/frontend/pweb/lib/pages/payment_methods/widgets/payment_info_section.dart index 745cd046..705b45e3 100644 --- a/frontend/pweb/lib/pages/payment_methods/widgets/payment_info_section.dart +++ b/frontend/pweb/lib/pages/payment_methods/widgets/payment_info_section.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:pshared/models/payment/methods/data.dart'; +import 'package:pshared/models/payment/methods/type.dart'; import 'package:pshared/provider/payment/flow.dart'; import 'package:pweb/pages/payment_methods/form.dart'; @@ -10,10 +11,11 @@ import 'package:pweb/pages/payment_methods/widgets/section_title.dart'; import 'package:pweb/utils/dimensions.dart'; import 'package:pweb/utils/payment/availability.dart'; import 'package:pweb/utils/payment/selector_type.dart'; +import 'package:pweb/utils/payment/label.dart'; import 'package:pweb/generated/i18n/app_localizations.dart'; - +//TODO Whole page sucks. Will redesign. class PaymentInfoSection extends StatelessWidget { final AppDimensions dimensions; @@ -31,6 +33,9 @@ class PaymentInfoSection extends StatelessWidget { final disabledTypesForSelection = hasRecipient ? disabledPaymentTypes.difference(resolvedAvailableTypes.keys.toSet()) : disabledPaymentTypes; + final methodsForSelectedType = flowProvider.methodsForSelectedType; + final selectedMethod = flowProvider.selectedMethod ?? + (methodsForSelectedType.isNotEmpty ? methodsForSelectedType.first : null); if (hasRecipient && resolvedAvailableTypes.isEmpty) { return Text(loc.recipientNoPaymentDetails); @@ -53,6 +58,30 @@ class PaymentInfoSection extends StatelessWidget { ), ), SizedBox(height: dimensions.paddingMedium), + if (hasRecipient && methodsForSelectedType.length > 1) + DropdownButtonFormField( + value: selectedMethod, + dropdownColor: Theme.of(context).colorScheme.onSecondary, + decoration: InputDecoration( + labelText: loc.paymentMethodDetails, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), + ), + items: methodsForSelectedType.map((method) { + final description = getPaymentTypeDescription(context, method); + final label = method.name.isNotEmpty ? '${method.name} - $description' : description; + return DropdownMenuItem( + value: method, + child: Text(label), + ); + }).toList(), + onChanged: (value) { + if (value != null) { + flowProvider.selectMethod(value); + } + }, + ), + if (hasRecipient && methodsForSelectedType.length > 1) + SizedBox(height: dimensions.paddingMedium), PaymentMethodForm( selectedType: selectedType, onChanged: (data) {