Compare commits
7 Commits
d978e24a9d
...
SEND017
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ddd7718c2 | ||
| b96babdfd4 | |||
| 69fdbf4e95 | |||
|
|
d32b2aa959 | ||
|
|
be10839e3a | ||
| d530af43a1 | |||
|
|
aa673fb26d |
@@ -39,10 +39,10 @@ chains:
|
|||||||
native_token: TRX
|
native_token: TRX
|
||||||
rpc_url_env: CHAIN_GATEWAY_RPC_URL
|
rpc_url_env: CHAIN_GATEWAY_RPC_URL
|
||||||
gas_topup_policy:
|
gas_topup_policy:
|
||||||
buffer_percent: 0.15
|
buffer_percent: 0.10
|
||||||
min_native_balance_trx: 20
|
min_native_balance_trx: 10
|
||||||
rounding_unit_trx: 1
|
rounding_unit_trx: 1
|
||||||
max_topup_trx: 500
|
max_topup_trx: 100
|
||||||
tokens:
|
tokens:
|
||||||
- symbol: USDT
|
- symbol: USDT
|
||||||
contract: "0xa614f803b6fd780986a42c78ec9c7f77e6ded13c"
|
contract: "0xa614f803b6fd780986a42c78ec9c7f77e6ded13c"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"github.com/tech/sendico/gateway/chain/internal/service/gateway/commands/wallet"
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/commands/wallet"
|
||||||
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/driver/evm"
|
||||||
"github.com/tech/sendico/gateway/chain/internal/service/gateway/driver/tron"
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/driver/tron"
|
||||||
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
||||||
"github.com/tech/sendico/gateway/chain/storage/model"
|
"github.com/tech/sendico/gateway/chain/storage/model"
|
||||||
@@ -171,6 +172,14 @@ func computeGasTopUp(ctx context.Context, deps Deps, walletRef string, estimated
|
|||||||
return topUp, decision.CapHit, &decision, nativeBalance, walletModel, nil
|
return topUp, decision.CapHit, &decision, nativeBalance, walletModel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if networkCfg.GasTopUpPolicy != nil {
|
||||||
|
topUp, capHit, err := evm.ComputeGasTopUp(networkCfg, walletModel, estimatedFee, nativeBalance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
return topUp, capHit, nil, nativeBalance, walletModel, nil
|
||||||
|
}
|
||||||
|
|
||||||
topUp, err := defaultGasTopUp(estimatedFee, nativeBalance)
|
topUp, err := defaultGasTopUp(estimatedFee, nativeBalance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, nil, nil, nil, err
|
return nil, false, nil, nil, nil, err
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package evm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
||||||
|
"github.com/tech/sendico/gateway/chain/storage/model"
|
||||||
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var evmBaseUnitFactor = decimal.NewFromInt(1_000_000_000_000_000_000)
|
||||||
|
|
||||||
|
// ComputeGasTopUp applies the network policy to decide an EVM native-token top-up amount.
|
||||||
|
func ComputeGasTopUp(network shared.Network, wallet *model.ManagedWallet, estimatedFee *moneyv1.Money, currentBalance *moneyv1.Money) (*moneyv1.Money, bool, error) {
|
||||||
|
if wallet == nil {
|
||||||
|
return nil, false, merrors.InvalidArgument("wallet is required")
|
||||||
|
}
|
||||||
|
if estimatedFee == nil || strings.TrimSpace(estimatedFee.GetAmount()) == "" || strings.TrimSpace(estimatedFee.GetCurrency()) == "" {
|
||||||
|
return nil, false, merrors.InvalidArgument("estimated fee is required")
|
||||||
|
}
|
||||||
|
if currentBalance == nil || strings.TrimSpace(currentBalance.GetAmount()) == "" || strings.TrimSpace(currentBalance.GetCurrency()) == "" {
|
||||||
|
return nil, false, merrors.InvalidArgument("current native balance is required")
|
||||||
|
}
|
||||||
|
if network.GasTopUpPolicy == nil {
|
||||||
|
return nil, false, merrors.InvalidArgument("gas top-up policy is not configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeCurrency := strings.TrimSpace(network.NativeToken)
|
||||||
|
if nativeCurrency == "" {
|
||||||
|
nativeCurrency = strings.ToUpper(strings.TrimSpace(network.Name))
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(nativeCurrency, estimatedFee.GetCurrency()) {
|
||||||
|
return nil, false, merrors.InvalidArgument(fmt.Sprintf("estimated fee currency mismatch (expected %s)", nativeCurrency))
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(nativeCurrency, currentBalance.GetCurrency()) {
|
||||||
|
return nil, false, merrors.InvalidArgument(fmt.Sprintf("native balance currency mismatch (expected %s)", nativeCurrency))
|
||||||
|
}
|
||||||
|
|
||||||
|
estimatedNative, err := evmToNative(estimatedFee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
currentNative, err := evmToNative(currentBalance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isContract := strings.TrimSpace(wallet.ContractAddress) != ""
|
||||||
|
rule, ok := network.GasTopUpPolicy.Rule(isContract)
|
||||||
|
if !ok {
|
||||||
|
return nil, false, merrors.InvalidArgument("gas top-up policy is not configured")
|
||||||
|
}
|
||||||
|
if rule.RoundingUnit.LessThanOrEqual(decimal.Zero) {
|
||||||
|
return nil, false, merrors.InvalidArgument("gas top-up rounding unit must be > 0")
|
||||||
|
}
|
||||||
|
if rule.MaxTopUp.LessThanOrEqual(decimal.Zero) {
|
||||||
|
return nil, false, merrors.InvalidArgument("gas top-up max top-up must be > 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
required := estimatedNative.Sub(currentNative)
|
||||||
|
if required.IsNegative() {
|
||||||
|
required = decimal.Zero
|
||||||
|
}
|
||||||
|
bufferedRequired := required.Mul(decimal.NewFromInt(1).Add(rule.BufferPercent))
|
||||||
|
|
||||||
|
minBalanceTopUp := rule.MinNativeBalance.Sub(currentNative)
|
||||||
|
if minBalanceTopUp.IsNegative() {
|
||||||
|
minBalanceTopUp = decimal.Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTopUp := bufferedRequired
|
||||||
|
if minBalanceTopUp.GreaterThan(rawTopUp) {
|
||||||
|
rawTopUp = minBalanceTopUp
|
||||||
|
}
|
||||||
|
|
||||||
|
roundedTopUp := decimal.Zero
|
||||||
|
if rawTopUp.IsPositive() {
|
||||||
|
roundedTopUp = rawTopUp.Div(rule.RoundingUnit).Ceil().Mul(rule.RoundingUnit)
|
||||||
|
}
|
||||||
|
|
||||||
|
topUp := roundedTopUp
|
||||||
|
capHit := false
|
||||||
|
if topUp.GreaterThan(rule.MaxTopUp) {
|
||||||
|
topUp = rule.MaxTopUp
|
||||||
|
capHit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !topUp.IsPositive() {
|
||||||
|
return nil, capHit, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUnits := topUp.Mul(evmBaseUnitFactor).Ceil().Truncate(0)
|
||||||
|
return &moneyv1.Money{
|
||||||
|
Currency: strings.ToUpper(nativeCurrency),
|
||||||
|
Amount: baseUnits.StringFixed(0),
|
||||||
|
}, capHit, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func evmToNative(amount *moneyv1.Money) (decimal.Decimal, error) {
|
||||||
|
value, err := decimal.NewFromString(strings.TrimSpace(amount.GetAmount()))
|
||||||
|
if err != nil {
|
||||||
|
return decimal.Zero, err
|
||||||
|
}
|
||||||
|
return value.Div(evmBaseUnitFactor), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
package evm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
||||||
|
"github.com/tech/sendico/gateway/chain/storage/model"
|
||||||
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_BalanceSufficient(t *testing.T) {
|
||||||
|
network := ethNetwork(defaultPolicy())
|
||||||
|
wallet := &model.ManagedWallet{}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("5"), ethMoney("30"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, topUp)
|
||||||
|
require.False(t, capHit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_BufferedRequired(t *testing.T) {
|
||||||
|
network := ethNetwork(defaultPolicy())
|
||||||
|
wallet := &model.ManagedWallet{}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("50"), ethMoney("10"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, topUp)
|
||||||
|
require.False(t, capHit)
|
||||||
|
require.Equal(t, "46000000000000000000", topUp.GetAmount())
|
||||||
|
require.Equal(t, "ETH", topUp.GetCurrency())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_MinBalanceBinding(t *testing.T) {
|
||||||
|
network := ethNetwork(defaultPolicy())
|
||||||
|
wallet := &model.ManagedWallet{}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("5"), ethMoney("1"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, topUp)
|
||||||
|
require.False(t, capHit)
|
||||||
|
require.Equal(t, "19000000000000000000", topUp.GetAmount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_RoundsUp(t *testing.T) {
|
||||||
|
policy := shared.GasTopUpPolicy{
|
||||||
|
Default: shared.GasTopUpRule{
|
||||||
|
BufferPercent: decimal.NewFromFloat(0),
|
||||||
|
MinNativeBalance: decimal.NewFromFloat(0),
|
||||||
|
RoundingUnit: decimal.NewFromFloat(1),
|
||||||
|
MaxTopUp: decimal.NewFromFloat(100),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
network := ethNetwork(&policy)
|
||||||
|
wallet := &model.ManagedWallet{}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("1.1"), ethMoney("0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, topUp)
|
||||||
|
require.False(t, capHit)
|
||||||
|
require.Equal(t, "2000000000000000000", topUp.GetAmount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_CapHit(t *testing.T) {
|
||||||
|
policy := shared.GasTopUpPolicy{
|
||||||
|
Default: shared.GasTopUpRule{
|
||||||
|
BufferPercent: decimal.NewFromFloat(0),
|
||||||
|
MinNativeBalance: decimal.NewFromFloat(0),
|
||||||
|
RoundingUnit: decimal.NewFromFloat(1),
|
||||||
|
MaxTopUp: decimal.NewFromFloat(10),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
network := ethNetwork(&policy)
|
||||||
|
wallet := &model.ManagedWallet{}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("100"), ethMoney("0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, topUp)
|
||||||
|
require.True(t, capHit)
|
||||||
|
require.Equal(t, "10000000000000000000", topUp.GetAmount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_MinBalanceWhenRequiredZero(t *testing.T) {
|
||||||
|
network := ethNetwork(defaultPolicy())
|
||||||
|
wallet := &model.ManagedWallet{}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("0"), ethMoney("5"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, topUp)
|
||||||
|
require.False(t, capHit)
|
||||||
|
require.Equal(t, "15000000000000000000", topUp.GetAmount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeGasTopUp_ContractPolicyOverride(t *testing.T) {
|
||||||
|
policy := shared.GasTopUpPolicy{
|
||||||
|
Default: shared.GasTopUpRule{
|
||||||
|
BufferPercent: decimal.NewFromFloat(0.1),
|
||||||
|
MinNativeBalance: decimal.NewFromFloat(10),
|
||||||
|
RoundingUnit: decimal.NewFromFloat(1),
|
||||||
|
MaxTopUp: decimal.NewFromFloat(100),
|
||||||
|
},
|
||||||
|
Contract: &shared.GasTopUpRule{
|
||||||
|
BufferPercent: decimal.NewFromFloat(0.5),
|
||||||
|
MinNativeBalance: decimal.NewFromFloat(5),
|
||||||
|
RoundingUnit: decimal.NewFromFloat(1),
|
||||||
|
MaxTopUp: decimal.NewFromFloat(100),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
network := ethNetwork(&policy)
|
||||||
|
wallet := &model.ManagedWallet{ContractAddress: "0xcontract"}
|
||||||
|
|
||||||
|
topUp, capHit, err := ComputeGasTopUp(network, wallet, ethMoney("10"), ethMoney("0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, topUp)
|
||||||
|
require.False(t, capHit)
|
||||||
|
require.Equal(t, "15000000000000000000", topUp.GetAmount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultPolicy() *shared.GasTopUpPolicy {
|
||||||
|
return &shared.GasTopUpPolicy{
|
||||||
|
Default: shared.GasTopUpRule{
|
||||||
|
BufferPercent: decimal.NewFromFloat(0.15),
|
||||||
|
MinNativeBalance: decimal.NewFromFloat(20),
|
||||||
|
RoundingUnit: decimal.NewFromFloat(1),
|
||||||
|
MaxTopUp: decimal.NewFromFloat(500),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ethNetwork(policy *shared.GasTopUpPolicy) shared.Network {
|
||||||
|
return shared.Network{
|
||||||
|
Name: "ethereum_mainnet",
|
||||||
|
NativeToken: "ETH",
|
||||||
|
GasTopUpPolicy: policy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ethMoney(eth string) *moneyv1.Money {
|
||||||
|
value, _ := decimal.NewFromString(eth)
|
||||||
|
baseUnits := value.Mul(evmBaseUnitFactor).Truncate(0)
|
||||||
|
return &moneyv1.Money{
|
||||||
|
Currency: "ETH",
|
||||||
|
Amount: baseUnits.StringFixed(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,7 +59,7 @@ oracle:
|
|||||||
|
|
||||||
card_gateways:
|
card_gateways:
|
||||||
monetix:
|
monetix:
|
||||||
funding_address: "TXtjmjF99MhMdaMQrLopzcQ8cSBRLq5co8"
|
funding_address: "TGBDXEg9rxSqGFJDcb889zqTjDwx1bmLRF"
|
||||||
fee_wallet_ref: "694c124fd76f9f811ac57134"
|
fee_wallet_ref: "694c124fd76f9f811ac57134"
|
||||||
|
|
||||||
fee_ledger_accounts:
|
fee_ledger_accounts:
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:pshared/models/payment/methods/data.dart';
|
import 'package:pshared/models/payment/methods/data.dart';
|
||||||
import 'package:pshared/models/payment/type.dart';
|
import 'package:pshared/models/payment/type.dart';
|
||||||
import 'package:pshared/models/recipient/recipient.dart';
|
import 'package:pshared/models/recipient/recipient.dart';
|
||||||
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
|
|
||||||
|
|
||||||
class PaymentFlowProvider extends ChangeNotifier {
|
class PaymentFlowProvider extends ChangeNotifier {
|
||||||
PaymentType _selectedType;
|
PaymentType _selectedType;
|
||||||
PaymentMethodData? _manualPaymentData;
|
PaymentMethodData? _manualPaymentData;
|
||||||
|
MethodMap _availableTypes = {};
|
||||||
|
Recipient? _recipient;
|
||||||
|
|
||||||
PaymentFlowProvider({
|
PaymentFlowProvider({
|
||||||
required PaymentType initialType,
|
required PaymentType initialType,
|
||||||
@@ -15,57 +18,40 @@ class PaymentFlowProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
PaymentType get selectedType => _selectedType;
|
PaymentType get selectedType => _selectedType;
|
||||||
PaymentMethodData? get manualPaymentData => _manualPaymentData;
|
PaymentMethodData? get manualPaymentData => _manualPaymentData;
|
||||||
|
Recipient? get recipient => _recipient;
|
||||||
|
|
||||||
void sync({
|
bool get hasRecipient => _recipient != null;
|
||||||
|
|
||||||
|
MethodMap get availableTypes => hasRecipient
|
||||||
|
? _availableTypes
|
||||||
|
: {for (final type in PaymentType.values) type: null};
|
||||||
|
|
||||||
|
PaymentMethodData? get selectedPaymentData =>
|
||||||
|
hasRecipient ? _availableTypes[_selectedType] : _manualPaymentData;
|
||||||
|
|
||||||
|
void syncWith({
|
||||||
required Recipient? recipient,
|
required Recipient? recipient,
|
||||||
required MethodMap availableTypes,
|
required PaymentMethodsProvider methodsProvider,
|
||||||
PaymentType? preferredType,
|
PaymentType? preferredType,
|
||||||
}) {
|
}) =>
|
||||||
final resolvedType = _resolveSelectedType(
|
_applyState(
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
availableTypes: availableTypes,
|
availableTypes: methodsProvider.availableTypesForRecipient(recipient),
|
||||||
preferredType: preferredType,
|
preferredType: preferredType,
|
||||||
);
|
forceResetManualData: false,
|
||||||
|
);
|
||||||
var hasChanges = false;
|
|
||||||
if (resolvedType != _selectedType) {
|
|
||||||
_selectedType = resolvedType;
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipient != null && _manualPaymentData != null) {
|
|
||||||
_manualPaymentData = null;
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChanges) notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset({
|
void reset({
|
||||||
required Recipient? recipient,
|
required Recipient? recipient,
|
||||||
required MethodMap availableTypes,
|
required PaymentMethodsProvider methodsProvider,
|
||||||
PaymentType? preferredType,
|
PaymentType? preferredType,
|
||||||
}) {
|
}) =>
|
||||||
final resolvedType = _resolveSelectedType(
|
_applyState(
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
availableTypes: availableTypes,
|
availableTypes: methodsProvider.availableTypesForRecipient(recipient),
|
||||||
preferredType: preferredType,
|
preferredType: preferredType,
|
||||||
);
|
forceResetManualData: true,
|
||||||
|
);
|
||||||
var hasChanges = false;
|
|
||||||
|
|
||||||
if (resolvedType != _selectedType) {
|
|
||||||
_selectedType = resolvedType;
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_manualPaymentData != null) {
|
|
||||||
_manualPaymentData = null;
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChanges) notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectType(PaymentType type, {bool resetManualData = false}) {
|
void selectType(PaymentType type, {bool resetManualData = false}) {
|
||||||
if (_selectedType == type && (!resetManualData || _manualPaymentData == null)) {
|
if (_selectedType == type && (!resetManualData || _manualPaymentData == null)) {
|
||||||
@@ -107,4 +93,41 @@ class PaymentFlowProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
return availableTypes.keys.first;
|
return availableTypes.keys.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _applyState({
|
||||||
|
required Recipient? recipient,
|
||||||
|
required MethodMap availableTypes,
|
||||||
|
required PaymentType? preferredType,
|
||||||
|
required bool forceResetManualData,
|
||||||
|
}) {
|
||||||
|
final resolvedType = _resolveSelectedType(
|
||||||
|
recipient: recipient,
|
||||||
|
availableTypes: availableTypes,
|
||||||
|
preferredType: preferredType,
|
||||||
|
);
|
||||||
|
|
||||||
|
var hasChanges = false;
|
||||||
|
|
||||||
|
if (_recipient != recipient) {
|
||||||
|
_recipient = recipient;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mapEquals(_availableTypes, availableTypes)) {
|
||||||
|
_availableTypes = availableTypes;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedType != _selectedType) {
|
||||||
|
_selectedType = resolvedType;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((recipient != null || forceResetManualData) && _manualPaymentData != null) {
|
||||||
|
_manualPaymentData = null;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChanges) notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
|
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import 'package:pshared/api/requests/payment/quote.dart';
|
import 'package:pshared/api/requests/payment/quote.dart';
|
||||||
@@ -20,7 +18,6 @@ import 'package:pshared/provider/organizations.dart';
|
|||||||
import 'package:pshared/provider/payment/amount.dart';
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
import 'package:pshared/provider/payment/flow.dart';
|
import 'package:pshared/provider/payment/flow.dart';
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
|
||||||
import 'package:pshared/provider/resource.dart';
|
import 'package:pshared/provider/resource.dart';
|
||||||
import 'package:pshared/service/payment/quotation.dart';
|
import 'package:pshared/service/payment/quotation.dart';
|
||||||
import 'package:pshared/utils/currency.dart';
|
import 'package:pshared/utils/currency.dart';
|
||||||
@@ -36,12 +33,10 @@ class QuotationProvider extends ChangeNotifier {
|
|||||||
PaymentAmountProvider payment,
|
PaymentAmountProvider payment,
|
||||||
WalletsProvider wallets,
|
WalletsProvider wallets,
|
||||||
PaymentFlowProvider flow,
|
PaymentFlowProvider flow,
|
||||||
PaymentMethodsProvider methods,
|
|
||||||
) {
|
) {
|
||||||
_organizations = venue;
|
_organizations = venue;
|
||||||
final t = flow.selectedType;
|
final destination = flow.selectedPaymentData;
|
||||||
final method = methods.methods.firstWhereOrNull((m) => m.type == t);
|
if ((wallets.selectedWallet != null) && (destination != null)) {
|
||||||
if ((wallets.selectedWallet != null) && (method != null)) {
|
|
||||||
getQuotation(PaymentIntent(
|
getQuotation(PaymentIntent(
|
||||||
kind: PaymentKind.payout,
|
kind: PaymentKind.payout,
|
||||||
amount: Money(
|
amount: Money(
|
||||||
@@ -49,7 +44,7 @@ class QuotationProvider extends ChangeNotifier {
|
|||||||
// TODO: adapt to possible other sources
|
// TODO: adapt to possible other sources
|
||||||
currency: currencyCodeToString(wallets.selectedWallet!.currency),
|
currency: currencyCodeToString(wallets.selectedWallet!.currency),
|
||||||
),
|
),
|
||||||
destination: method.data,
|
destination: destination,
|
||||||
source: ManagedWalletPaymentMethod(
|
source: ManagedWalletPaymentMethod(
|
||||||
managedWalletRef: wallets.selectedWallet!.id,
|
managedWalletRef: wallets.selectedWallet!.id,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import 'package:pshared/models/describable.dart';
|
|||||||
import 'package:pshared/models/organization/bound.dart';
|
import 'package:pshared/models/organization/bound.dart';
|
||||||
import 'package:pshared/models/payment/methods/data.dart';
|
import 'package:pshared/models/payment/methods/data.dart';
|
||||||
import 'package:pshared/models/payment/methods/type.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/models/permissions/bound.dart';
|
import 'package:pshared/models/permissions/bound.dart';
|
||||||
import 'package:pshared/models/storable.dart';
|
import 'package:pshared/models/storable.dart';
|
||||||
import 'package:pshared/provider/organizations.dart';
|
import 'package:pshared/provider/organizations.dart';
|
||||||
@@ -20,6 +22,24 @@ class PaymentMethodsProvider extends GenericProvider<PaymentMethod> {
|
|||||||
|
|
||||||
List<PaymentMethod> get methods => List<PaymentMethod>.unmodifiable(items.toList()..sort((a, b) => a.storable.createdAt.compareTo(b.storable.createdAt)));
|
List<PaymentMethod> get methods => List<PaymentMethod>.unmodifiable(items.toList()..sort((a, b) => a.storable.createdAt.compareTo(b.storable.createdAt)));
|
||||||
|
|
||||||
|
List<PaymentMethod> methodsForRecipient(Recipient? recipient) {
|
||||||
|
if (recipient == null || !isReady) return [];
|
||||||
|
|
||||||
|
return methods
|
||||||
|
.where((method) => !method.isArchived && method.recipientRef == recipient.id)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodMap availableTypesForRecipient(Recipient? recipient) => {
|
||||||
|
for (final method in methodsForRecipient(recipient)) method.type: method.data,
|
||||||
|
};
|
||||||
|
|
||||||
|
PaymentMethod? findMethodByType({
|
||||||
|
required PaymentType type,
|
||||||
|
required Recipient? recipient,
|
||||||
|
}) =>
|
||||||
|
methodsForRecipient(recipient).firstWhereOrNull((method) => method.type == type);
|
||||||
|
|
||||||
void updateProviders(OrganizationsProvider organizations, RecipientsProvider recipients) {
|
void updateProviders(OrganizationsProvider organizations, RecipientsProvider recipients) {
|
||||||
if (recipients.currentObject != null) loadMethods(organizations, recipients.currentObject?.id);
|
if (recipients.currentObject != null) loadMethods(organizations, recipients.currentObject?.id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import 'package:pshared/provider/organizations.dart';
|
|||||||
import 'package:pshared/provider/payment/amount.dart';
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
import 'package:pshared/service/payment/wallets.dart';
|
||||||
|
|
||||||
import 'package:pweb/app/app.dart';
|
import 'package:pweb/app/app.dart';
|
||||||
import 'package:pweb/app/timeago.dart';
|
import 'package:pweb/app/timeago.dart';
|
||||||
@@ -23,13 +25,11 @@ import 'package:pweb/providers/mock_payment.dart';
|
|||||||
import 'package:pweb/providers/operatioins.dart';
|
import 'package:pweb/providers/operatioins.dart';
|
||||||
import 'package:pweb/providers/two_factor.dart';
|
import 'package:pweb/providers/two_factor.dart';
|
||||||
import 'package:pweb/providers/upload_history.dart';
|
import 'package:pweb/providers/upload_history.dart';
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
|
||||||
import 'package:pweb/providers/wallet_transactions.dart';
|
import 'package:pweb/providers/wallet_transactions.dart';
|
||||||
import 'package:pweb/services/operations.dart';
|
import 'package:pweb/services/operations.dart';
|
||||||
import 'package:pweb/services/payments/history.dart';
|
import 'package:pweb/services/payments/history.dart';
|
||||||
import 'package:pweb/services/posthog.dart';
|
import 'package:pweb/services/posthog.dart';
|
||||||
import 'package:pweb/services/wallet_transactions.dart';
|
import 'package:pweb/services/wallet_transactions.dart';
|
||||||
import 'package:pshared/service/payment/wallets.dart';
|
|
||||||
import 'package:pweb/providers/account.dart';
|
import 'package:pweb/providers/account.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import 'package:pshared/provider/payment/amount.dart';
|
|||||||
import 'package:pshared/provider/payment/flow.dart';
|
import 'package:pshared/provider/payment/flow.dart';
|
||||||
import 'package:pshared/provider/payment/quotation.dart';
|
import 'package:pshared/provider/payment/quotation.dart';
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/payouts/form.dart';
|
import 'package:pweb/pages/dashboard/payouts/form.dart';
|
||||||
|
|
||||||
@@ -21,11 +20,11 @@ class PaymentFromWrappingWidget extends StatelessWidget {
|
|||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (_) => PaymentAmountProvider(),
|
create: (_) => PaymentAmountProvider(),
|
||||||
),
|
),
|
||||||
ChangeNotifierProxyProvider5<OrganizationsProvider, PaymentAmountProvider, WalletsProvider, PaymentFlowProvider, PaymentMethodsProvider, QuotationProvider>(
|
ChangeNotifierProxyProvider4<OrganizationsProvider, PaymentAmountProvider, WalletsProvider, PaymentFlowProvider, QuotationProvider>(
|
||||||
create: (_) => QuotationProvider(),
|
create: (_) => QuotationProvider(),
|
||||||
update: (context, orgnization, payment, wallet, flow, methods, provider) => provider!..update(orgnization, payment, wallet, flow, methods),
|
update: (context, orgnization, payment, wallet, flow, provider) => provider!..update(orgnization, payment, wallet, flow),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: const PaymentFormWidget(),
|
child: const PaymentFormWidget(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,10 +67,17 @@ class _CardFormMinimalState extends State<CardFormMinimal> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newData != null && newData != oldData) {
|
if (newData != null && newData != oldData) {
|
||||||
_panController.text = newData.pan;
|
final hasPanChange = newData.pan != _panController.text;
|
||||||
_firstNameController.text = newData.firstName;
|
final hasFirstNameChange = newData.firstName != _firstNameController.text;
|
||||||
_lastNameController.text = newData.lastName;
|
final hasLastNameChange = newData.lastName != _lastNameController.text;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
|
||||||
|
if (hasPanChange) _panController.text = newData.pan;
|
||||||
|
if (hasFirstNameChange) _firstNameController.text = newData.firstName;
|
||||||
|
if (hasLastNameChange) _lastNameController.text = newData.lastName;
|
||||||
|
|
||||||
|
if (hasPanChange || hasFirstNameChange || hasLastNameChange) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,12 +106,21 @@ class _CryptoAddressFormState extends State<CryptoAddressForm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newData != null && newData != oldData) {
|
if (newData != null && newData != oldData) {
|
||||||
_addressCtrl.text = newData.address;
|
final hasAddressChange = newData.address != _addressCtrl.text;
|
||||||
_tokenCtrl.text = newData.asset?.tokenSymbol ?? '';
|
final hasTokenChange = newData.asset?.tokenSymbol != _tokenCtrl.text;
|
||||||
_contractCtrl.text = newData.asset?.contractAddress ?? '';
|
final hasContractChange = newData.asset?.contractAddress != _contractCtrl.text;
|
||||||
_memoCtrl.text = newData.memo ?? '';
|
final hasMemoChange = newData.memo != _memoCtrl.text;
|
||||||
_chain = newData.asset?.chain ?? ChainNetwork.unspecified;
|
final hasChainChange = newData.asset?.chain != _chain;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
|
||||||
|
if (hasAddressChange) _addressCtrl.text = newData.address;
|
||||||
|
if (hasTokenChange) _tokenCtrl.text = newData.asset?.tokenSymbol ?? '';
|
||||||
|
if (hasContractChange) _contractCtrl.text = newData.asset?.contractAddress ?? '';
|
||||||
|
if (hasMemoChange) _memoCtrl.text = newData.memo ?? '';
|
||||||
|
if (hasChainChange) _chain = newData.asset?.chain ?? ChainNetwork.unspecified;
|
||||||
|
|
||||||
|
if (hasAddressChange || hasTokenChange || hasContractChange || hasMemoChange || hasChainChange) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,11 +69,19 @@ class _IbanFormState extends State<IbanForm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newData != null && newData != oldData) {
|
if (newData != null && newData != oldData) {
|
||||||
_ibanController.text = newData.iban;
|
final hasIbanChange = newData.iban != _ibanController.text;
|
||||||
_accountHolderController.text = newData.accountHolder;
|
final hasHolderChange = newData.accountHolder != _accountHolderController.text;
|
||||||
_bicController.text = newData.bic ?? '';
|
final hasBicChange = (newData.bic ?? '') != _bicController.text;
|
||||||
_bankNameController.text = newData.bankName ?? '';
|
final hasBankNameChange = (newData.bankName ?? '') != _bankNameController.text;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
|
||||||
|
if (hasIbanChange) _ibanController.text = newData.iban;
|
||||||
|
if (hasHolderChange) _accountHolderController.text = newData.accountHolder;
|
||||||
|
if (hasBicChange) _bicController.text = newData.bic ?? '';
|
||||||
|
if (hasBankNameChange) _bankNameController.text = newData.bankName ?? '';
|
||||||
|
|
||||||
|
if (hasIbanChange || hasHolderChange || hasBicChange || hasBankNameChange) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,14 +82,31 @@ class _RussianBankFormState extends State<RussianBankForm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newData != null && newData != oldData) {
|
if (newData != null && newData != oldData) {
|
||||||
_recipientNameController.text = newData.recipientName;
|
final hasRecipientNameChange = newData.recipientName != _recipientNameController.text;
|
||||||
_innController.text = newData.inn;
|
final hasInnChange = newData.inn != _innController.text;
|
||||||
_kppController.text = newData.kpp;
|
final hasKppChange = newData.kpp != _kppController.text;
|
||||||
_bankNameController.text = newData.bankName;
|
final hasBankNameChange = newData.bankName != _bankNameController.text;
|
||||||
_bikController.text = newData.bik;
|
final hasBikChange = newData.bik != _bikController.text;
|
||||||
_accountNumberController.text = newData.accountNumber;
|
final hasAccountNumberChange = newData.accountNumber != _accountNumberController.text;
|
||||||
_correspondentAccountController.text = newData.correspondentAccount;
|
final hasCorrespondentAccountChange = newData.correspondentAccount != _correspondentAccountController.text;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
|
||||||
|
if (hasRecipientNameChange) _recipientNameController.text = newData.recipientName;
|
||||||
|
if (hasInnChange) _innController.text = newData.inn;
|
||||||
|
if (hasKppChange) _kppController.text = newData.kpp;
|
||||||
|
if (hasBankNameChange) _bankNameController.text = newData.bankName;
|
||||||
|
if (hasBikChange) _bikController.text = newData.bik;
|
||||||
|
if (hasAccountNumberChange) _accountNumberController.text = newData.accountNumber;
|
||||||
|
if (hasCorrespondentAccountChange) _correspondentAccountController.text = newData.correspondentAccount;
|
||||||
|
|
||||||
|
if (hasRecipientNameChange ||
|
||||||
|
hasInnChange ||
|
||||||
|
hasKppChange ||
|
||||||
|
hasBankNameChange ||
|
||||||
|
hasBikChange ||
|
||||||
|
hasAccountNumberChange ||
|
||||||
|
hasCorrespondentAccountChange) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ class _WalletFormState extends State<WalletForm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newData != null && newData != oldData) {
|
if (newData != null && newData != oldData) {
|
||||||
_walletIdController.text = newData.walletId;
|
if (newData.walletId != _walletIdController.text) {
|
||||||
|
_walletIdController.text = newData.walletId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ import 'package:collection/collection.dart';
|
|||||||
|
|
||||||
import 'package:provider/provider.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/methods/type.dart';
|
||||||
import 'package:pshared/models/payment/type.dart';
|
import 'package:pshared/models/payment/type.dart';
|
||||||
import 'package:pshared/models/recipient/recipient.dart';
|
import 'package:pshared/models/recipient/recipient.dart';
|
||||||
import 'package:pshared/provider/payment/flow.dart';
|
import 'package:pshared/provider/payment/flow.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.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:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:pweb/pages/payment_methods/payment_page/body.dart';
|
||||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||||
import 'package:pweb/services/posthog.dart';
|
import 'package:pweb/services/posthog.dart';
|
||||||
|
|
||||||
@@ -38,16 +38,12 @@ class PaymentPage extends StatefulWidget {
|
|||||||
class _PaymentPageState extends State<PaymentPage> {
|
class _PaymentPageState extends State<PaymentPage> {
|
||||||
late final TextEditingController _searchController;
|
late final TextEditingController _searchController;
|
||||||
late final FocusNode _searchFocusNode;
|
late final FocusNode _searchFocusNode;
|
||||||
late final PaymentFlowProvider _flowProvider;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_searchController = TextEditingController();
|
_searchController = TextEditingController();
|
||||||
_searchFocusNode = FocusNode();
|
_searchFocusNode = FocusNode();
|
||||||
_flowProvider = PaymentFlowProvider(
|
|
||||||
initialType: widget.initialPaymentType ?? PaymentType.bankAccount,
|
|
||||||
);
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _initializePaymentPage());
|
WidgetsBinding.instance.addPostFrameCallback((_) => _initializePaymentPage());
|
||||||
}
|
}
|
||||||
@@ -56,20 +52,12 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_searchController.dispose();
|
_searchController.dispose();
|
||||||
_searchFocusNode.dispose();
|
_searchFocusNode.dispose();
|
||||||
_flowProvider.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initializePaymentPage() {
|
void _initializePaymentPage() {
|
||||||
final methodsProvider = context.read<PaymentMethodsProvider>();
|
final methodsProvider = context.read<PaymentMethodsProvider>();
|
||||||
_handleWalletAutoSelection(methodsProvider);
|
_handleWalletAutoSelection(methodsProvider);
|
||||||
|
|
||||||
final recipient = context.read<RecipientsProvider>().currentObject;
|
|
||||||
_syncFlowProvider(
|
|
||||||
recipient: recipient,
|
|
||||||
methodsProvider: methodsProvider,
|
|
||||||
preferredType: widget.initialPaymentType,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSearchChanged(String query) {
|
void _handleSearchChanged(String query) {
|
||||||
@@ -79,11 +67,12 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
void _handleRecipientSelected(Recipient recipient) {
|
void _handleRecipientSelected(Recipient recipient) {
|
||||||
final recipientProvider = context.read<RecipientsProvider>();
|
final recipientProvider = context.read<RecipientsProvider>();
|
||||||
final methodsProvider = context.read<PaymentMethodsProvider>();
|
final methodsProvider = context.read<PaymentMethodsProvider>();
|
||||||
|
final flowProvider = context.read<PaymentFlowProvider>();
|
||||||
|
|
||||||
recipientProvider.setCurrentObject(recipient.id);
|
recipientProvider.setCurrentObject(recipient.id);
|
||||||
_flowProvider.reset(
|
flowProvider.reset(
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
availableTypes: _availablePaymentTypes(recipient, methodsProvider),
|
methodsProvider: methodsProvider,
|
||||||
preferredType: widget.initialPaymentType,
|
preferredType: widget.initialPaymentType,
|
||||||
);
|
);
|
||||||
_clearSearchField();
|
_clearSearchField();
|
||||||
@@ -92,11 +81,12 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
void _handleRecipientCleared() {
|
void _handleRecipientCleared() {
|
||||||
final recipientProvider = context.read<RecipientsProvider>();
|
final recipientProvider = context.read<RecipientsProvider>();
|
||||||
final methodsProvider = context.read<PaymentMethodsProvider>();
|
final methodsProvider = context.read<PaymentMethodsProvider>();
|
||||||
|
final flowProvider = context.read<PaymentFlowProvider>();
|
||||||
|
|
||||||
recipientProvider.setCurrentObject(null);
|
recipientProvider.setCurrentObject(null);
|
||||||
_flowProvider.reset(
|
flowProvider.reset(
|
||||||
recipient: null,
|
recipient: null,
|
||||||
availableTypes: _availablePaymentTypes(null, methodsProvider),
|
methodsProvider: methodsProvider,
|
||||||
preferredType: widget.initialPaymentType,
|
preferredType: widget.initialPaymentType,
|
||||||
);
|
);
|
||||||
_clearSearchField();
|
_clearSearchField();
|
||||||
@@ -110,7 +100,7 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
|
|
||||||
void _handleSendPayment() {
|
void _handleSendPayment() {
|
||||||
// TODO: Handle Payment logic
|
// TODO: Handle Payment logic
|
||||||
PosthogService.paymentInitiated(method: _flowProvider.selectedType);
|
PosthogService.paymentInitiated(method: context.read<PaymentFlowProvider>().selectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -118,23 +108,29 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
final methodsProvider = context.watch<PaymentMethodsProvider>();
|
final methodsProvider = context.watch<PaymentMethodsProvider>();
|
||||||
final recipientProvider = context.watch<RecipientsProvider>();
|
final recipientProvider = context.watch<RecipientsProvider>();
|
||||||
final recipient = recipientProvider.currentObject;
|
final recipient = recipientProvider.currentObject;
|
||||||
final availableTypes = _availablePaymentTypes(recipient, methodsProvider);
|
|
||||||
|
|
||||||
_syncFlowProvider(
|
return ChangeNotifierProxyProvider2<RecipientsProvider, PaymentMethodsProvider, PaymentFlowProvider>(
|
||||||
recipient: recipient,
|
create: (_) => PaymentFlowProvider(
|
||||||
methodsProvider: methodsProvider,
|
initialType: widget.initialPaymentType ?? PaymentType.bankAccount,
|
||||||
preferredType: recipient != null ? widget.initialPaymentType : null,
|
),
|
||||||
);
|
update: (_, recipients, methods, flow) {
|
||||||
|
final provider = flow ?? PaymentFlowProvider(
|
||||||
return ChangeNotifierProvider.value(
|
initialType: widget.initialPaymentType ?? PaymentType.bankAccount,
|
||||||
value: _flowProvider,
|
);
|
||||||
|
final currentRecipient = recipients.currentObject;
|
||||||
|
provider.syncWith(
|
||||||
|
recipient: currentRecipient,
|
||||||
|
methodsProvider: methods,
|
||||||
|
preferredType: currentRecipient != null ? widget.initialPaymentType : null,
|
||||||
|
);
|
||||||
|
return provider;
|
||||||
|
},
|
||||||
child: PaymentPageBody(
|
child: PaymentPageBody(
|
||||||
onBack: widget.onBack,
|
onBack: widget.onBack,
|
||||||
fallbackDestination: widget.fallbackDestination,
|
fallbackDestination: widget.fallbackDestination,
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
recipientProvider: recipientProvider,
|
recipientProvider: recipientProvider,
|
||||||
methodsProvider: methodsProvider,
|
methodsProvider: methodsProvider,
|
||||||
availablePaymentTypes: availableTypes,
|
|
||||||
searchController: _searchController,
|
searchController: _searchController,
|
||||||
searchFocusNode: _searchFocusNode,
|
searchFocusNode: _searchFocusNode,
|
||||||
onSearchChanged: _handleSearchChanged,
|
onSearchChanged: _handleSearchChanged,
|
||||||
@@ -155,33 +151,6 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _syncFlowProvider({
|
|
||||||
required Recipient? recipient,
|
|
||||||
required PaymentMethodsProvider methodsProvider,
|
|
||||||
PaymentType? preferredType,
|
|
||||||
}) {
|
|
||||||
_flowProvider.sync(
|
|
||||||
recipient: recipient,
|
|
||||||
availableTypes: _availablePaymentTypes(recipient, methodsProvider),
|
|
||||||
preferredType: preferredType,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
PaymentMethod? _getPaymentMethodForWallet(
|
||||||
Wallet wallet,
|
Wallet wallet,
|
||||||
PaymentMethodsProvider methodsProvider,
|
PaymentMethodsProvider methodsProvider,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/methods/data.dart';
|
|
||||||
import 'package:pshared/models/recipient/recipient.dart';
|
import 'package:pshared/models/recipient/recipient.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
@@ -17,7 +16,6 @@ class PaymentPageBody extends StatelessWidget {
|
|||||||
final Recipient? recipient;
|
final Recipient? recipient;
|
||||||
final RecipientsProvider recipientProvider;
|
final RecipientsProvider recipientProvider;
|
||||||
final PaymentMethodsProvider methodsProvider;
|
final PaymentMethodsProvider methodsProvider;
|
||||||
final MethodMap availablePaymentTypes;
|
|
||||||
final PayoutDestination fallbackDestination;
|
final PayoutDestination fallbackDestination;
|
||||||
final TextEditingController searchController;
|
final TextEditingController searchController;
|
||||||
final FocusNode searchFocusNode;
|
final FocusNode searchFocusNode;
|
||||||
@@ -32,7 +30,6 @@ class PaymentPageBody extends StatelessWidget {
|
|||||||
required this.recipient,
|
required this.recipient,
|
||||||
required this.recipientProvider,
|
required this.recipientProvider,
|
||||||
required this.methodsProvider,
|
required this.methodsProvider,
|
||||||
required this.availablePaymentTypes,
|
|
||||||
required this.fallbackDestination,
|
required this.fallbackDestination,
|
||||||
required this.searchController,
|
required this.searchController,
|
||||||
required this.searchFocusNode,
|
required this.searchFocusNode,
|
||||||
@@ -61,7 +58,6 @@ class PaymentPageBody extends StatelessWidget {
|
|||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
recipientProvider: recipientProvider,
|
recipientProvider: recipientProvider,
|
||||||
methodsProvider: methodsProvider,
|
methodsProvider: methodsProvider,
|
||||||
availablePaymentTypes: availablePaymentTypes,
|
|
||||||
fallbackDestination: fallbackDestination,
|
fallbackDestination: fallbackDestination,
|
||||||
searchController: searchController,
|
searchController: searchController,
|
||||||
searchFocusNode: searchFocusNode,
|
searchFocusNode: searchFocusNode,
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'package:pshared/models/payment/methods/data.dart';
|
|
||||||
import 'package:pshared/models/recipient/recipient.dart';
|
import 'package:pshared/models/recipient/recipient.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
import 'package:pshared/provider/payment/flow.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/header.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/header.dart';
|
||||||
@@ -27,7 +23,6 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
final Recipient? recipient;
|
final Recipient? recipient;
|
||||||
final RecipientsProvider recipientProvider;
|
final RecipientsProvider recipientProvider;
|
||||||
final PaymentMethodsProvider methodsProvider;
|
final PaymentMethodsProvider methodsProvider;
|
||||||
final MethodMap availablePaymentTypes;
|
|
||||||
final PayoutDestination fallbackDestination;
|
final PayoutDestination fallbackDestination;
|
||||||
final TextEditingController searchController;
|
final TextEditingController searchController;
|
||||||
final FocusNode searchFocusNode;
|
final FocusNode searchFocusNode;
|
||||||
@@ -42,7 +37,6 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
required this.recipient,
|
required this.recipient,
|
||||||
required this.recipientProvider,
|
required this.recipientProvider,
|
||||||
required this.methodsProvider,
|
required this.methodsProvider,
|
||||||
required this.availablePaymentTypes,
|
|
||||||
required this.fallbackDestination,
|
required this.fallbackDestination,
|
||||||
required this.searchController,
|
required this.searchController,
|
||||||
required this.searchFocusNode,
|
required this.searchFocusNode,
|
||||||
@@ -55,7 +49,6 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final dimensions = AppDimensions();
|
final dimensions = AppDimensions();
|
||||||
final flowProvider = context.watch<PaymentFlowProvider>();
|
|
||||||
final loc = AppLocalizations.of(context)!;
|
final loc = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
return Align(
|
return Align(
|
||||||
@@ -98,12 +91,7 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
onRecipientCleared: onRecipientCleared,
|
onRecipientCleared: onRecipientCleared,
|
||||||
),
|
),
|
||||||
SizedBox(height: dimensions.paddingXLarge),
|
SizedBox(height: dimensions.paddingXLarge),
|
||||||
PaymentInfoSection(
|
PaymentInfoSection(dimensions: dimensions),
|
||||||
dimensions: dimensions,
|
|
||||||
flowProvider: flowProvider,
|
|
||||||
recipient: recipient,
|
|
||||||
availableTypes: availablePaymentTypes,
|
|
||||||
),
|
|
||||||
SizedBox(height: dimensions.paddingLarge),
|
SizedBox(height: dimensions.paddingLarge),
|
||||||
const PaymentFormWidget(),
|
const PaymentFormWidget(),
|
||||||
SizedBox(height: dimensions.paddingXXXLarge),
|
SizedBox(height: dimensions.paddingXXXLarge),
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'package:pshared/models/payment/methods/data.dart';
|
|
||||||
import 'package:pshared/models/recipient/recipient.dart';
|
import 'package:pshared/models/recipient/recipient.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
import 'package:pshared/provider/payment/flow.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/payouts/widget.dart';
|
import 'package:pweb/pages/dashboard/payouts/widget.dart';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
|
||||||
@@ -27,7 +23,6 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
final Recipient? recipient;
|
final Recipient? recipient;
|
||||||
final RecipientsProvider recipientProvider;
|
final RecipientsProvider recipientProvider;
|
||||||
final PaymentMethodsProvider methodsProvider;
|
final PaymentMethodsProvider methodsProvider;
|
||||||
final MethodMap availablePaymentTypes;
|
|
||||||
final PayoutDestination fallbackDestination;
|
final PayoutDestination fallbackDestination;
|
||||||
final TextEditingController searchController;
|
final TextEditingController searchController;
|
||||||
final FocusNode searchFocusNode;
|
final FocusNode searchFocusNode;
|
||||||
@@ -42,7 +37,6 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
required this.recipient,
|
required this.recipient,
|
||||||
required this.recipientProvider,
|
required this.recipientProvider,
|
||||||
required this.methodsProvider,
|
required this.methodsProvider,
|
||||||
required this.availablePaymentTypes,
|
|
||||||
required this.fallbackDestination,
|
required this.fallbackDestination,
|
||||||
required this.searchController,
|
required this.searchController,
|
||||||
required this.searchFocusNode,
|
required this.searchFocusNode,
|
||||||
@@ -55,7 +49,6 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final dimensions = AppDimensions();
|
final dimensions = AppDimensions();
|
||||||
final flowProvider = context.watch<PaymentFlowProvider>();
|
|
||||||
final loc = AppLocalizations.of(context)!;
|
final loc = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
return Align(
|
return Align(
|
||||||
@@ -98,12 +91,7 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
onRecipientCleared: onRecipientCleared,
|
onRecipientCleared: onRecipientCleared,
|
||||||
),
|
),
|
||||||
SizedBox(height: dimensions.paddingXLarge),
|
SizedBox(height: dimensions.paddingXLarge),
|
||||||
PaymentInfoSection(
|
PaymentInfoSection(dimensions: dimensions),
|
||||||
dimensions: dimensions,
|
|
||||||
flowProvider: flowProvider,
|
|
||||||
recipient: recipient,
|
|
||||||
availableTypes: availablePaymentTypes,
|
|
||||||
),
|
|
||||||
SizedBox(height: dimensions.paddingLarge),
|
SizedBox(height: dimensions.paddingLarge),
|
||||||
const PaymentFromWrappingWidget(),
|
const PaymentFromWrappingWidget(),
|
||||||
SizedBox(height: dimensions.paddingXXXLarge),
|
SizedBox(height: dimensions.paddingXXXLarge),
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/methods/data.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/provider/payment/flow.dart';
|
import 'package:pshared/provider/payment/flow.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/payment_methods/form.dart';
|
import 'package:pweb/pages/payment_methods/form.dart';
|
||||||
@@ -15,25 +14,18 @@ import 'package:pweb/generated/i18n/app_localizations.dart';
|
|||||||
|
|
||||||
class PaymentInfoSection extends StatelessWidget {
|
class PaymentInfoSection extends StatelessWidget {
|
||||||
final AppDimensions dimensions;
|
final AppDimensions dimensions;
|
||||||
final MethodMap availableTypes;
|
|
||||||
final PaymentFlowProvider flowProvider;
|
|
||||||
final Recipient? recipient;
|
|
||||||
|
|
||||||
const PaymentInfoSection({
|
const PaymentInfoSection({
|
||||||
super.key,
|
super.key,
|
||||||
required this.dimensions,
|
required this.dimensions,
|
||||||
required this.availableTypes,
|
|
||||||
required this.flowProvider,
|
|
||||||
required this.recipient,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final loc = AppLocalizations.of(context)!;
|
final loc = AppLocalizations.of(context)!;
|
||||||
final hasRecipient = recipient != null;
|
final flowProvider = context.watch<PaymentFlowProvider>();
|
||||||
final MethodMap resolvedAvailableTypes = hasRecipient
|
final hasRecipient = flowProvider.hasRecipient;
|
||||||
? availableTypes
|
final MethodMap resolvedAvailableTypes = flowProvider.availableTypes;
|
||||||
: {for (final type in PaymentType.values) type: null};
|
|
||||||
|
|
||||||
if (hasRecipient && resolvedAvailableTypes.isEmpty) {
|
if (hasRecipient && resolvedAvailableTypes.isEmpty) {
|
||||||
return Text(loc.recipientNoPaymentDetails);
|
return Text(loc.recipientNoPaymentDetails);
|
||||||
@@ -62,7 +54,7 @@ class PaymentInfoSection extends StatelessWidget {
|
|||||||
flowProvider.setManualPaymentData(data);
|
flowProvider.setManualPaymentData(data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initialData: hasRecipient ? resolvedAvailableTypes[selectedType] : flowProvider.manualPaymentData,
|
initialData: flowProvider.selectedPaymentData,
|
||||||
isEditable: !hasRecipient,
|
isEditable: !hasRecipient,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/payout_page/methods/widget.dart';
|
import 'package:pweb/pages/payout_page/methods/widget.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/wigets.dart';
|
import 'package:pweb/pages/payout_page/wallet/wigets.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/utils/currency.dart';
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/type.dart';
|
import 'package:pshared/models/payment/type.dart';
|
||||||
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
import 'package:pweb/app/router/payout_routes.dart';
|
import 'package:pweb/app/router/payout_routes.dart';
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
|
||||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pweb/app/router/payout_routes.dart';
|
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/app/router/payout_routes.dart';
|
||||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import 'package:flutter/services.dart';
|
|||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
||||||
|
|
||||||
|
|
||||||
class WalletEditFields extends StatelessWidget {
|
class WalletEditFields extends StatelessWidget {
|
||||||
const WalletEditFields({super.key});
|
const WalletEditFields({super.key});
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/payout_page/wallet/edit/buttons/buttons.dart';
|
import 'package:pweb/pages/payout_page/wallet/edit/buttons/buttons.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/edit/fields.dart';
|
import 'package:pweb/pages/payout_page/wallet/edit/fields.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/edit/header.dart';
|
import 'package:pweb/pages/payout_page/wallet/edit/header.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/history/history.dart';
|
import 'package:pweb/pages/payout_page/wallet/history/history.dart';
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
|
||||||
import 'package:pweb/utils/dimensions.dart';
|
import 'package:pweb/utils/dimensions.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/payout_page/wallet/history/filters.dart';
|
import 'package:pweb/pages/payout_page/wallet/history/filters.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/history/table.dart';
|
import 'package:pweb/pages/payout_page/wallet/history/table.dart';
|
||||||
import 'package:pweb/providers/wallet_transactions.dart';
|
import 'package:pweb/providers/wallet_transactions.dart';
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/card.dart';
|
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/payout_page/wallet/card.dart';
|
||||||
|
|
||||||
|
|
||||||
class WalletWidgets extends StatelessWidget {
|
class WalletWidgets extends StatelessWidget {
|
||||||
final void Function(Wallet) onWalletTap;
|
final void Function(Wallet) onWalletTap;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:pshared/models/payment/chain_network.dart';
|
import 'package:pshared/models/payment/chain_network.dart';
|
||||||
import 'package:pshared/utils/currency.dart';
|
import 'package:pshared/utils/currency.dart';
|
||||||
import 'package:pshared/utils/l10n/chain.dart';
|
import 'package:pshared/utils/l10n/chain.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/wallet_top_up/details.dart';
|
import 'package:pweb/pages/wallet_top_up/details.dart';
|
||||||
import 'package:pweb/pages/wallet_top_up/header.dart';
|
import 'package:pweb/pages/wallet_top_up/header.dart';
|
||||||
import 'package:pweb/pages/wallet_top_up/meta.dart';
|
import 'package:pweb/pages/wallet_top_up/meta.dart';
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/wallet_top_up/content.dart';
|
|
||||||
import 'package:pshared/provider/payment/wallets.dart';
|
import 'package:pshared/provider/payment/wallets.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/wallet_top_up/content.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user