200 lines
6.9 KiB
Dart
200 lines
6.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:collection/collection.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/models/payment/type.dart';
|
|
import 'package:pshared/models/recipient/recipient.dart';
|
|
import 'package:pshared/provider/organizations.dart';
|
|
import 'package:pshared/provider/payment/amount.dart';
|
|
import 'package:pshared/provider/payment/flow.dart';
|
|
import 'package:pshared/provider/payment/provider.dart';
|
|
import 'package:pshared/provider/payment/quotation.dart';
|
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
|
import 'package:pshared/provider/recipient/provider.dart';
|
|
|
|
import 'package:pshared/models/payment/wallet.dart';
|
|
import 'package:pweb/pages/payment_methods/payment_page/body.dart';
|
|
import 'package:pshared/provider/payment/wallets.dart';
|
|
import 'package:pweb/widgets/sidebar/destinations.dart';
|
|
import 'package:pweb/services/posthog.dart';
|
|
|
|
|
|
class PaymentPage extends StatefulWidget {
|
|
final ValueChanged<Recipient?>? onBack;
|
|
final PaymentType? initialPaymentType;
|
|
final PayoutDestination fallbackDestination;
|
|
|
|
const PaymentPage({
|
|
super.key,
|
|
this.onBack,
|
|
this.initialPaymentType,
|
|
this.fallbackDestination = PayoutDestination.dashboard,
|
|
});
|
|
|
|
@override
|
|
State<PaymentPage> createState() => _PaymentPageState();
|
|
}
|
|
|
|
class _PaymentPageState extends State<PaymentPage> {
|
|
late final TextEditingController _searchController;
|
|
late final FocusNode _searchFocusNode;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_searchController = TextEditingController();
|
|
_searchFocusNode = FocusNode();
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) => _initializePaymentPage());
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_searchController.dispose();
|
|
_searchFocusNode.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _initializePaymentPage() {
|
|
final methodsProvider = context.read<PaymentMethodsProvider>();
|
|
_handleWalletAutoSelection(methodsProvider);
|
|
}
|
|
|
|
void _handleSearchChanged(String query) {
|
|
context.read<RecipientsProvider>().setQuery(query);
|
|
}
|
|
|
|
void _handleRecipientSelected(BuildContext context, Recipient recipient) {
|
|
final recipientProvider = context.read<RecipientsProvider>();
|
|
recipientProvider.setCurrentObject(recipient.id);
|
|
_clearSearchField();
|
|
}
|
|
|
|
void _handleRecipientCleared(BuildContext context) {
|
|
final recipientProvider = context.read<RecipientsProvider>();
|
|
final methodsProvider = context.read<PaymentMethodsProvider>();
|
|
|
|
recipientProvider.setCurrentObject(null);
|
|
context.read<PaymentFlowProvider>().reset(
|
|
recipient: null,
|
|
availableTypes: _availablePaymentTypes(null, methodsProvider),
|
|
preferredType: widget.initialPaymentType,
|
|
);
|
|
_clearSearchField();
|
|
}
|
|
|
|
void _clearSearchField() {
|
|
_searchController.clear();
|
|
_searchFocusNode.unfocus();
|
|
context.read<RecipientsProvider>().setQuery('');
|
|
}
|
|
|
|
void _handleSendPayment(BuildContext context) {
|
|
if (context.read<QuotationProvider>().isReady) {
|
|
context.read<PaymentProvider>().pay();
|
|
PosthogService.paymentInitiated(
|
|
method: context.read<PaymentFlowProvider>().selectedType,
|
|
);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final methodsProvider = context.watch<PaymentMethodsProvider>();
|
|
final recipientProvider = context.watch<RecipientsProvider>();
|
|
final recipient = recipientProvider.currentObject;
|
|
final availableTypes = _availablePaymentTypes(recipient, methodsProvider);
|
|
|
|
return MultiProvider(
|
|
providers: [
|
|
ChangeNotifierProxyProvider2<RecipientsProvider, PaymentMethodsProvider, PaymentFlowProvider>(
|
|
create: (_) => PaymentFlowProvider(
|
|
initialType: widget.initialPaymentType ?? PaymentType.bankAccount,
|
|
),
|
|
update: (_, recipients, methods, flow) {
|
|
final currentRecipient = recipients.currentObject;
|
|
flow!.sync(
|
|
recipient: currentRecipient,
|
|
availableTypes: _availablePaymentTypes(currentRecipient, methods),
|
|
preferredType: currentRecipient != null ? widget.initialPaymentType : null,
|
|
);
|
|
return flow;
|
|
},
|
|
),
|
|
ChangeNotifierProvider(
|
|
create: (_) => PaymentAmountProvider(),
|
|
),
|
|
ChangeNotifierProxyProvider6<OrganizationsProvider, PaymentAmountProvider, WalletsProvider, PaymentFlowProvider, RecipientsProvider, PaymentMethodsProvider, QuotationProvider>(
|
|
create: (_) => QuotationProvider(),
|
|
update: (_, organization, payment, wallet, flow, recipients, methods, provider) =>
|
|
provider!..update(organization, payment, wallet, flow, recipients, methods),
|
|
),
|
|
ChangeNotifierProxyProvider2<OrganizationsProvider, QuotationProvider, PaymentProvider>(
|
|
create: (_) => PaymentProvider(),
|
|
update: (_, organization, quotation, provider) => provider!..update(organization, quotation),
|
|
),
|
|
],
|
|
child: Builder(
|
|
builder: (innerContext) => PaymentPageBody(
|
|
onBack: widget.onBack,
|
|
fallbackDestination: widget.fallbackDestination,
|
|
recipient: recipient,
|
|
recipientProvider: recipientProvider,
|
|
methodsProvider: methodsProvider,
|
|
availablePaymentTypes: availableTypes,
|
|
searchController: _searchController,
|
|
searchFocusNode: _searchFocusNode,
|
|
onSearchChanged: _handleSearchChanged,
|
|
onRecipientSelected: (selected) => _handleRecipientSelected(innerContext, selected),
|
|
onRecipientCleared: () => _handleRecipientCleared(innerContext),
|
|
onSend: () => _handleSendPayment(innerContext),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _handleWalletAutoSelection(PaymentMethodsProvider methodsProvider) {
|
|
final wallet = context.read<WalletsProvider>().selectedWallet;
|
|
if (wallet == null) return;
|
|
|
|
final matchingMethod = _getPaymentMethodForWallet(wallet, methodsProvider);
|
|
if (matchingMethod != null) {
|
|
methodsProvider.setCurrentObject(matchingMethod.id);
|
|
}
|
|
}
|
|
|
|
MethodMap _availablePaymentTypes(
|
|
Recipient? recipient,
|
|
PaymentMethodsProvider methodsProvider,
|
|
) {
|
|
if (recipient == null || !methodsProvider.isReady) return {};
|
|
|
|
final methodsForRecipient = methodsProvider.methods.where(
|
|
(method) => !method.isArchived && method.recipientRef == recipient.id,
|
|
);
|
|
|
|
return {
|
|
for (final method in methodsForRecipient) method.type: method.data,
|
|
};
|
|
}
|
|
|
|
PaymentMethod? _getPaymentMethodForWallet(
|
|
Wallet wallet,
|
|
PaymentMethodsProvider methodsProvider,
|
|
) {
|
|
if (methodsProvider.methods.isEmpty) {
|
|
return null;
|
|
}
|
|
|
|
return methodsProvider.methods.firstWhereOrNull(
|
|
(method) =>
|
|
method.type == PaymentType.wallet &&
|
|
(method.description?.contains(wallet.walletUserID) ?? false),
|
|
);
|
|
}
|
|
}
|