Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On-ramp: Add redux-thunk, refactor successful order handler #6257

Merged
merged 3 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 4 additions & 97 deletions app/components/UI/FiatOnRampAggregator/Views/Checkout.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,32 @@
import React, { useCallback, useEffect, useState } from 'react';
import { View } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { parseUrl } from 'query-string';
import { WebView, WebViewNavigation } from 'react-native-webview';
import { useNavigation } from '@react-navigation/native';
import { CryptoCurrency, Order, Provider } from '@consensys/on-ramp-sdk';
import { Provider } from '@consensys/on-ramp-sdk';
import { baseStyles } from '../../../../styles/common';
import { useTheme } from '../../../../util/theme';
import { getFiatOnRampAggNavbar } from '../../Navbar';
import { NATIVE_ADDRESS } from '../../../../constants/on-ramp';
import { useFiatOnRampSDK, SDK } from '../sdk';
import {
addFiatCustomIdData,
addFiatOrder,
FiatOrder,
removeFiatCustomIdData,
} from '../../../../reducers/fiatOrders';
import { CustomIdData } from '../../../../reducers/fiatOrders/types';
import Engine from '../../../../core/Engine';
import { toLowerCaseEquals } from '../../../../util/general';
import {
createNavigationDetails,
useParams,
} from '../../../../util/navigation/navUtils';
import { hexToBN } from '../../../../util/number';
import { protectWalletModalVisible } from '../../../../actions/user';
import { aggregatorOrderToFiatOrder } from '../orderProcessor/aggregator';
import { createCustomOrderIdData } from '../orderProcessor/customOrderId';
import { getNotificationDetails } from '..';
import NotificationManager from '../../../../core/NotificationManager';
import ScreenLayout from '../components/ScreenLayout';
import ErrorView from '../components/ErrorView';
import ErrorViewWithReporting from '../components/ErrorViewWithReporting';
import useAnalytics from '../hooks/useAnalytics';
import { strings } from '../../../../../locales/i18n';
import Routes from '../../../../constants/navigation/Routes';
import useHandleSuccessfulOrder from '../hooks/useHandleSuccessfulOrder';

interface CheckoutParams {
url: string;
Expand All @@ -58,10 +50,7 @@ const CheckoutWebView = () => {
const navigation = useNavigation();
const params = useParams<CheckoutParams>();
const { colors } = useTheme();
const accounts = useSelector(
(state: any) =>
state.engine.backgroundState.AccountTrackerController.accounts,
);
const handleSuccessfulOrder = useHandleSuccessfulOrder();

const { url: uri, customOrderId, provider } = params;

Expand Down Expand Up @@ -97,88 +86,6 @@ const CheckoutWebView = () => {
dispatch(addFiatCustomIdData(customOrderIdData));
}, [customOrderId, dispatch, selectedAddress, selectedChainId]);

const addTokenToTokensController = useCallback(
async (token: CryptoCurrency) => {
if (!token) return;

const { address, symbol, decimals, network, name } = token;
const chainId = network?.chainId;

if (
Number(chainId) !== Number(selectedChainId) ||
address === NATIVE_ADDRESS
) {
return;
}

// @ts-expect-error Engine context typing
const { TokensController } = Engine.context;

if (
!TokensController.state.tokens.includes((t: any) =>
toLowerCaseEquals(t.address, address),
)
) {
await TokensController.addToken(address, symbol, decimals, null, name);
}
},
[selectedChainId],
);

const handleAddFiatOrder = useCallback(
(order) => {
dispatch(addFiatOrder(order));
},
[dispatch],
);

const handleDispatchUserWalletProtection = useCallback(() => {
dispatch(protectWalletModalVisible());
}, [dispatch]);

const handleSuccessfulOrder = useCallback(
async (order) => {
// add the order to the redux global store
handleAddFiatOrder(order);
// register the token automatically
await addTokenToTokensController((order as any)?.data?.cryptoCurrency);

// prompt user to protect his/her wallet
handleDispatchUserWalletProtection();
// close the checkout webview
// @ts-expect-error navigation prop mismatch
navigation.dangerouslyGetParent()?.pop();
NotificationManager.showSimpleNotification(
getNotificationDetails(order as any),
);
trackEvent('ONRAMP_PURCHASE_SUBMITTED', {
provider_onramp: ((order as FiatOrder)?.data as Order)?.provider?.name,
payment_method_id: ((order as FiatOrder)?.data as Order)?.paymentMethod
?.id,
currency_source: ((order as FiatOrder)?.data as Order)?.fiatCurrency
.symbol,
currency_destination: ((order as FiatOrder)?.data as Order)
?.cryptoCurrency.symbol,
chain_id_destination: selectedChainId,
order_type: (order as FiatOrder)?.orderType,
is_apple_pay: false,
has_zero_native_balance: accounts[selectedAddress]?.balance
? (hexToBN(accounts[selectedAddress].balance) as any)?.isZero?.()
: undefined,
});
},
[
accounts,
addTokenToTokensController,
handleAddFiatOrder,
handleDispatchUserWalletProtection,
navigation,
selectedAddress,
selectedChainId,
trackEvent,
],
);

const handleNavigationStateChange = async (navState: WebViewNavigation) => {
if (
!isRedirectionHandled &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { Order, QuoteResponse } from '@consensys/on-ramp-sdk';
import { protectWalletModalNotVisible } from '../../../../actions/user';
import { QuoteResponse } from '@consensys/on-ramp-sdk';
import {
addAuthenticationUrl,
addFiatOrder,
FiatOrder,
} from '../../../../reducers/fiatOrders';
import ApplePayButtonComponent from '../components/ApplePayButton';
import useApplePay, { ABORTED } from '../hooks/useApplePay';
import useAnalytics from '../hooks/useAnalytics';
import Logger from '../../../../util/Logger';
import { strings } from '../../../../../locales/i18n';
import { setLockTime } from '../../../../actions/settings';
import { aggregatorOrderToFiatOrder } from '../orderProcessor/aggregator';
import { getNotificationDetails } from '..';
import NotificationManager from '../../../../core/NotificationManager';
import { hexToBN } from '../../../../util/number';
import { useFiatOnRampSDK } from '../sdk';
import useHandleSuccessfulOrder from '../hooks/useHandleSuccessfulOrder';

function buildAuthenticationUrl(url: string, redirectUrl: string) {
const urlObject = new URL(url);
Expand All @@ -36,66 +31,13 @@ const ApplePayButton = ({
quote: QuoteResponse;
label: string;
}) => {
const navigation = useNavigation();
const dispatch = useDispatch();
const trackEvent = useAnalytics();
const { selectedAddress, selectedChainId, callbackBaseUrl } =
useFiatOnRampSDK();
const accounts = useSelector(
(state: any) =>
state.engine.backgroundState.AccountTrackerController.accounts,
);

const dispatch = useDispatch();
const [pay] = useApplePay(quote);
const handleSuccessfulOrder = useHandleSuccessfulOrder();
const lockTime = useSelector((state: any) => state.settings.lockTime);

const addOrder = useCallback(
(order) => dispatch(addFiatOrder(order)),
[dispatch],
);
const protectWalletModalVisible = useCallback(
() => dispatch(protectWalletModalNotVisible()),
[dispatch],
);

const handleSuccessfulOrder = useCallback(
(order) => {
const fiatOrder: FiatOrder = {
...aggregatorOrderToFiatOrder(order),
network: selectedChainId,
account: selectedAddress,
};
addOrder(fiatOrder);
// @ts-expect-error pop is not defined
navigation.dangerouslyGetParent()?.pop();
protectWalletModalVisible();
NotificationManager.showSimpleNotification(
getNotificationDetails(fiatOrder),
);
trackEvent('ONRAMP_PURCHASE_SUBMITTED', {
provider_onramp: (fiatOrder?.data as Order)?.provider?.name,
payment_method_id: (fiatOrder?.data as Order)?.paymentMethod?.id,
currency_source: (fiatOrder?.data as Order)?.fiatCurrency.symbol,
currency_destination: (fiatOrder?.data as Order)?.cryptoCurrency.symbol,
chain_id_destination: selectedChainId,
is_apple_pay: true,
order_type: fiatOrder.orderType,
has_zero_native_balance: accounts[selectedAddress]?.balance
? (hexToBN(accounts[selectedAddress].balance) as any)?.isZero?.()
: undefined,
});
},
[
accounts,
addOrder,
selectedChainId,
navigation,
protectWalletModalVisible,
selectedAddress,
trackEvent,
],
);

const handlePress = useCallback(async () => {
const prevLockTime = lockTime;
dispatch(setLockTime(-1));
Expand All @@ -109,8 +51,14 @@ const ApplePayButton = ({
);
dispatch(addAuthenticationUrl(authenticationUrl));
}

handleSuccessfulOrder(paymentResult.order);
if (paymentResult.order) {
const fiatOrder: FiatOrder = {
...aggregatorOrderToFiatOrder(paymentResult.order),
network: selectedChainId,
account: selectedAddress,
};
handleSuccessfulOrder(fiatOrder, { isApplePay: true });
}
}
} catch (error: any) {
NotificationManager.showSimpleNotification({
Expand All @@ -130,6 +78,8 @@ const ApplePayButton = ({
dispatch,
pay,
callbackBaseUrl,
selectedChainId,
selectedAddress,
handleSuccessfulOrder,
quote.crypto?.symbol,
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { CryptoCurrency, Order } from '@consensys/on-ramp-sdk';
import { hexToBN } from '@metamask/controller-utils';
import { useNavigation } from '@react-navigation/native';
import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getNotificationDetails } from '..';
import { protectWalletModalVisible } from '../../../../actions/user';
import { NATIVE_ADDRESS } from '../../../../constants/on-ramp';
import Engine from '../../../../core/Engine';
import NotificationManager from '../../../../core/NotificationManager';
import { addFiatOrder, FiatOrder } from '../../../../reducers/fiatOrders';
import { toLowerCaseEquals } from '../../../../util/general';
import useThunkDispatch from '../../../hooks/useThunkDispatch';
import { useFiatOnRampSDK } from '../sdk';
import { stateHasOrder } from '../utils';
import useAnalytics from './useAnalytics';

function useHandleSuccessfulOrder() {
const { selectedChainId, selectedAddress } = useFiatOnRampSDK();
const navigation = useNavigation();
const dispatch = useDispatch();
const dispatchThunk = useThunkDispatch();
const trackEvent = useAnalytics();
const accounts = useSelector(
(state: any) =>
state.engine.backgroundState.AccountTrackerController.accounts,
);

const addTokenToTokensController = useCallback(
async (token: CryptoCurrency) => {
if (!token) return;

const { address, symbol, decimals, network, name } = token;
const chainId = network?.chainId;

if (
Number(chainId) !== Number(selectedChainId) ||
address === NATIVE_ADDRESS
) {
return;
}

const { TokensController } = Engine.context;

if (
!TokensController.state.tokens.includes((t: any) =>
toLowerCaseEquals(t.address, address),
)
) {
await TokensController.addToken(address, symbol, decimals, null, name);
}
},
[selectedChainId],
);

const handleDispatchUserWalletProtection = useCallback(() => {
dispatch(protectWalletModalVisible());
}, [dispatch]);

const handleAddFiatOrder = useCallback(
(order) => {
dispatch(addFiatOrder(order));
},
[dispatch],
);

const handleSuccessfulOrder = useCallback(
async (
order: FiatOrder,
params?: {
isApplePay?: boolean;
},
) => {
await addTokenToTokensController((order as any)?.data?.cryptoCurrency);
handleDispatchUserWalletProtection();
// @ts-expect-error navigation prop mismatch
navigation.dangerouslyGetParent()?.pop();

dispatchThunk((_, getState) => {
const state = getState();
if (stateHasOrder(state, order)) {
return;
}
handleAddFiatOrder(order);
NotificationManager.showSimpleNotification(
getNotificationDetails(order as any),
);
trackEvent('ONRAMP_PURCHASE_SUBMITTED', {
provider_onramp: (order?.data as Order)?.provider?.name,
payment_method_id: (order?.data as Order)?.paymentMethod?.id,
currency_source: (order?.data as Order)?.fiatCurrency.symbol,
currency_destination: (order?.data as Order)?.cryptoCurrency.symbol,
chain_id_destination: selectedChainId,
order_type: order?.orderType,
is_apple_pay: Boolean(params?.isApplePay),
has_zero_native_balance: accounts[selectedAddress]?.balance
? (hexToBN(accounts[selectedAddress].balance) as any)?.isZero?.()
: undefined,
});
});
},
[
accounts,
addTokenToTokensController,
dispatchThunk,
handleAddFiatOrder,
handleDispatchUserWalletProtection,
navigation,
selectedAddress,
selectedChainId,
trackEvent,
],
);

return handleSuccessfulOrder;
}

export default useHandleSuccessfulOrder;
Loading