ledger top up functionality and few small fixes for project architechture and design
This commit is contained in:
@@ -5,19 +5,21 @@ import 'package:pshared/models/recipient/recipient.dart';
|
||||
|
||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||
import 'package:pweb/controllers/payments/page_ui.dart';
|
||||
import 'package:pweb/pages/payout_page/send/page_handlers.dart';
|
||||
import 'package:pweb/utils/payment/page_handlers.dart';
|
||||
import 'package:pweb/pages/payout_page/send/page_view.dart';
|
||||
|
||||
|
||||
class PaymentPage extends StatefulWidget {
|
||||
final ValueChanged<Recipient?>? onBack;
|
||||
final PaymentType? initialPaymentType;
|
||||
final String? initialDestinationLedgerAccountRef;
|
||||
final PayoutDestination fallbackDestination;
|
||||
|
||||
const PaymentPage({
|
||||
super.key,
|
||||
this.onBack,
|
||||
this.initialPaymentType,
|
||||
this.initialDestinationLedgerAccountRef,
|
||||
this.fallbackDestination = PayoutDestination.dashboard,
|
||||
});
|
||||
|
||||
@@ -34,7 +36,11 @@ class _PaymentPageState extends State<PaymentPage> {
|
||||
_uiController = PaymentPageUiController();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => initializePaymentPage(context, widget.initialPaymentType),
|
||||
(_) => initializePaymentPage(
|
||||
context,
|
||||
widget.initialPaymentType,
|
||||
destinationLedgerAccountRef: widget.initialDestinationLedgerAccountRef,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/payment/flow.dart';
|
||||
import 'package:pshared/provider/payment/provider.dart';
|
||||
import 'package:pshared/provider/payment/quotation/quotation.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/app/router/payout_routes.dart';
|
||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||
import 'package:pweb/widgets/dialogs/payment_status_dialog.dart';
|
||||
import 'package:pweb/controllers/payments/page.dart';
|
||||
import 'package:pweb/controllers/payments/page_ui.dart';
|
||||
import 'package:pweb/controllers/payouts/payout_verification.dart';
|
||||
import 'package:pweb/utils/payment/payout_verification_flow.dart';
|
||||
|
||||
void initializePaymentPage(
|
||||
BuildContext context,
|
||||
PaymentType? initialPaymentType,
|
||||
) {
|
||||
final flowProvider = context.read<PaymentFlowProvider>();
|
||||
flowProvider.setPreferredType(initialPaymentType);
|
||||
}
|
||||
|
||||
void handleSearchChanged(PaymentPageUiController uiController, String query) {
|
||||
uiController.setQuery(query);
|
||||
}
|
||||
|
||||
void handleRecipientSelected(
|
||||
BuildContext context,
|
||||
PaymentPageUiController uiController,
|
||||
Recipient recipient,
|
||||
) {
|
||||
final recipientProvider = context.read<RecipientsProvider>();
|
||||
recipientProvider.setCurrentObject(recipient.id);
|
||||
uiController.clearSearch();
|
||||
}
|
||||
|
||||
void handleRecipientCleared(
|
||||
BuildContext context,
|
||||
PaymentPageUiController uiController,
|
||||
) {
|
||||
final recipientProvider = context.read<RecipientsProvider>();
|
||||
recipientProvider.setCurrentObject(null);
|
||||
uiController.clearSearch();
|
||||
}
|
||||
|
||||
Future<void> handleSendPayment({
|
||||
required State state,
|
||||
required PayoutDestination fallbackDestination,
|
||||
}) async {
|
||||
final context = state.context;
|
||||
final paymentProvider = context.read<PaymentProvider>();
|
||||
final quotationProvider = context.read<QuotationProvider>();
|
||||
final controller = context.read<PaymentPageController>();
|
||||
final verificationController = context.read<PayoutVerificationController>();
|
||||
if (paymentProvider.isLoading) return;
|
||||
final verificationContextKey =
|
||||
quotationProvider.quotation?.quoteRef ??
|
||||
quotationProvider.quotation?.idempotencyKey;
|
||||
|
||||
final verified = await runPayoutVerification(
|
||||
context: context,
|
||||
controller: verificationController,
|
||||
contextKey: verificationContextKey,
|
||||
);
|
||||
if (!verified || !state.mounted) return;
|
||||
|
||||
final isSuccess = await controller.sendPayment();
|
||||
if (!state.mounted) return;
|
||||
|
||||
await showPaymentStatusDialog(context, isSuccess: isSuccess);
|
||||
if (!state.mounted) return;
|
||||
|
||||
if (isSuccess) {
|
||||
controller.handleSuccess();
|
||||
context.goToPayout(fallbackDestination);
|
||||
}
|
||||
}
|
||||
|
||||
void handleAddRecipient(BuildContext context) {
|
||||
final recipients = context.read<RecipientsProvider>();
|
||||
recipients.setCurrentObject(null);
|
||||
context.pushToPayout(PayoutDestination.addrecipient);
|
||||
}
|
||||
|
||||
void handleAddPaymentMethod(BuildContext context) {
|
||||
final recipients = context.read<RecipientsProvider>();
|
||||
final recipient = recipients.currentObject;
|
||||
if (recipient == null) return;
|
||||
recipients.setCurrentObject(recipient.id);
|
||||
context.pushNamed(PayoutRoutes.editRecipient);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/payment/flow.dart';
|
||||
import 'package:pshared/provider/payment/quotation/quotation.dart';
|
||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
@@ -14,6 +15,7 @@ import 'package:pweb/controllers/payments/page_ui.dart';
|
||||
import 'package:pweb/controllers/payouts/payout_verification.dart';
|
||||
import 'package:pweb/models/state/control_state.dart';
|
||||
|
||||
|
||||
class PaymentPageView extends StatelessWidget {
|
||||
final PaymentPageUiController uiController;
|
||||
final ValueChanged<Recipient?>? onBack;
|
||||
@@ -47,6 +49,7 @@ class PaymentPageView extends StatelessWidget {
|
||||
final uiController = context.watch<PaymentPageUiController>();
|
||||
final methodsProvider = context.watch<PaymentMethodsProvider>();
|
||||
final recipientProvider = context.watch<RecipientsProvider>();
|
||||
final flowProvider = context.watch<PaymentFlowProvider>();
|
||||
final quotationProvider = context.watch<QuotationProvider>();
|
||||
final verificationController = context
|
||||
.watch<PayoutVerificationController>();
|
||||
@@ -58,10 +61,12 @@ class PaymentPageView extends StatelessWidget {
|
||||
recipients: recipientProvider.recipients,
|
||||
query: uiController.query,
|
||||
);
|
||||
final hasDestinationSelection =
|
||||
flowProvider.selectedPaymentData != null;
|
||||
final sendState =
|
||||
verificationController.isCooldownActiveFor(verificationContextKey)
|
||||
? ControlState.disabled
|
||||
: (recipient == null
|
||||
: (!hasDestinationSelection
|
||||
? ControlState.disabled
|
||||
: ControlState.enabled);
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/recipient/payment_method_draft.dart';
|
||||
|
||||
import 'package:pweb/pages/address_book/form/widgets/payment_methods/panel.dart';
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/header.dart';
|
||||
import 'package:pweb/models/state/control_state.dart';
|
||||
import 'package:pweb/models/state/visibility.dart';
|
||||
import 'package:pweb/utils/dimensions.dart';
|
||||
|
||||
|
||||
class PaymentInfoManualDetailsSection extends StatelessWidget {
|
||||
final AppDimensions dimensions;
|
||||
final String title;
|
||||
final VisibilityState titleVisibility;
|
||||
final PaymentMethodData data;
|
||||
|
||||
const PaymentInfoManualDetailsSection({
|
||||
super.key,
|
||||
required this.dimensions,
|
||||
required this.title,
|
||||
required this.titleVisibility,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final entry = RecipientMethodDraft(type: data.type, data: data);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
PaymentInfoHeader(
|
||||
dimensions: dimensions,
|
||||
title: title,
|
||||
visibility: titleVisibility,
|
||||
),
|
||||
PaymentMethodPanel(
|
||||
selectedType: data.type,
|
||||
selectedIndex: 0,
|
||||
entries: [entry],
|
||||
onRemove: (_) {},
|
||||
onChanged: (_, ignored) {},
|
||||
editState: ControlState.disabled,
|
||||
deleteVisibility: VisibilityState.hidden,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import 'package:pshared/provider/payment/flow.dart';
|
||||
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/methods_section.dart';
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/methods_state.dart';
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/manual_details.dart';
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/no_methods.dart';
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/no_recipient.dart';
|
||||
import 'package:pweb/models/state/visibility.dart';
|
||||
@@ -35,8 +36,9 @@ class PaymentInfoSection extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
final flowProvider = context.watch<PaymentFlowProvider>();
|
||||
final manualData = flowProvider.manualPaymentData;
|
||||
|
||||
if (!flowProvider.hasRecipient) {
|
||||
if (!flowProvider.hasRecipient && manualData == null) {
|
||||
return PaymentInfoNoRecipientSection(
|
||||
dimensions: dimensions,
|
||||
title: loc.paymentInfo,
|
||||
@@ -44,6 +46,15 @@ class PaymentInfoSection extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if (!flowProvider.hasRecipient && manualData != null) {
|
||||
return PaymentInfoManualDetailsSection(
|
||||
dimensions: dimensions,
|
||||
title: loc.paymentInfo,
|
||||
titleVisibility: titleVisibility,
|
||||
data: manualData,
|
||||
);
|
||||
}
|
||||
|
||||
final methods = flowProvider.methodsForRecipient;
|
||||
final types = visiblePaymentTypes;
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class RecipientSection extends StatelessWidget {
|
||||
ShortListAddressBookPayout(
|
||||
recipients: recipientProvider.recipients,
|
||||
onSelected: onRecipientSelected,
|
||||
trailing: AddRecipientTile(
|
||||
leading: AddRecipientTile(
|
||||
label: loc.addRecipient,
|
||||
onTap: onAddRecipient,
|
||||
),
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/payment/flow.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/pages/payout_page/send/widgets/payment_info/section.dart';
|
||||
@@ -46,24 +49,30 @@ class PaymentRecipientDetailsCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final flowProvider = context.watch<PaymentFlowProvider>();
|
||||
final isRecipientSelectionLocked =
|
||||
!flowProvider.hasRecipient && flowProvider.manualPaymentData != null;
|
||||
|
||||
return PaymentSectionCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RecipientSection(
|
||||
recipient: recipient,
|
||||
dimensions: dimensions,
|
||||
recipientProvider: recipientProvider,
|
||||
searchQuery: searchQuery,
|
||||
filteredRecipients: filteredRecipients,
|
||||
searchController: searchController,
|
||||
searchFocusNode: searchFocusNode,
|
||||
onSearchChanged: onSearchChanged,
|
||||
onRecipientSelected: onRecipientSelected,
|
||||
onRecipientCleared: onRecipientCleared,
|
||||
onAddRecipient: onAddRecipient,
|
||||
),
|
||||
SizedBox(height: dimensions.paddingMedium),
|
||||
if (!isRecipientSelectionLocked) ...[
|
||||
RecipientSection(
|
||||
recipient: recipient,
|
||||
dimensions: dimensions,
|
||||
recipientProvider: recipientProvider,
|
||||
searchQuery: searchQuery,
|
||||
filteredRecipients: filteredRecipients,
|
||||
searchController: searchController,
|
||||
searchFocusNode: searchFocusNode,
|
||||
onSearchChanged: onSearchChanged,
|
||||
onRecipientSelected: onRecipientSelected,
|
||||
onRecipientCleared: onRecipientCleared,
|
||||
onAddRecipient: onAddRecipient,
|
||||
),
|
||||
SizedBox(height: dimensions.paddingMedium),
|
||||
],
|
||||
PaymentInfoSection(
|
||||
dimensions: dimensions,
|
||||
titleVisibility: VisibilityState.hidden,
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/controllers/payment/source.dart';
|
||||
import 'package:pshared/models/payment/source_type.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/app/router/payout_routes.dart';
|
||||
|
||||
@@ -17,11 +21,35 @@ class TopUpButton extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
final source = context.watch<PaymentSourceController>();
|
||||
final canTopUp = source.selectedType == PaymentSourceType.wallet;
|
||||
final selectedType = source.selectedType;
|
||||
final selectedLedger = source.selectedLedgerAccount;
|
||||
final canTopUp =
|
||||
selectedType == PaymentSourceType.wallet ||
|
||||
(selectedType == PaymentSourceType.ledger && selectedLedger != null);
|
||||
|
||||
return ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(shadowColor: null, elevation: 0),
|
||||
onPressed: canTopUp ? () => context.pushToWalletTopUp() : null,
|
||||
onPressed: !canTopUp
|
||||
? null
|
||||
: () {
|
||||
if (selectedType == PaymentSourceType.wallet) {
|
||||
context.pushToWalletTopUp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedType == PaymentSourceType.ledger &&
|
||||
selectedLedger != null) {
|
||||
context.read<RecipientsProvider>().setCurrentObject(null);
|
||||
context.pushNamed(
|
||||
PayoutRoutes.payment,
|
||||
queryParameters: PayoutRoutes.buildQueryParameters(
|
||||
paymentType: PaymentType.ledger,
|
||||
destinationLedgerAccountRef:
|
||||
selectedLedger.ledgerAccountRef,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(loc.topUpBalance),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user