From 4cb47659f01d316fe659da666ea9875f15e3e9ce Mon Sep 17 00:00:00 2001 From: Pedro Pablo Aste Kompen Date: Fri, 5 Apr 2024 16:08:15 -0300 Subject: [PATCH 1/2] refactor(ramp,deeplink): add buy/sell actions and pass rampPath to handler --- app/constants/deeplinks.ts | 4 +++ .../DeeplinkManager/DeeplinkManager.test.ts | 25 ++++++++++++++++--- app/core/DeeplinkManager/DeeplinkManager.ts | 19 ++++++++++---- .../DeeplinkManager/Handlers/handleRampUrl.ts | 24 ++++++++++++++++++ .../ParseManager/handleMetaMaskDeeplink.ts | 20 ++++++++++++--- .../ParseManager/handleUniversalLink.ts | 14 ++++++++--- 6 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 app/core/DeeplinkManager/Handlers/handleRampUrl.ts diff --git a/app/constants/deeplinks.ts b/app/constants/deeplinks.ts index 20f2fc2be89..a0c57d472b9 100644 --- a/app/constants/deeplinks.ts +++ b/app/constants/deeplinks.ts @@ -21,7 +21,9 @@ export enum ACTIONS { WC = 'wc', CONNECT = 'connect', ANDROID_SDK = 'bind', + BUY = 'buy', BUY_CRYPTO = 'buy-crypto', + SELL = 'sell', SELL_CRYPTO = 'sell-crypto', EMPTY = '', } @@ -36,6 +38,8 @@ export const PREFIXES = { [ACTIONS.WC]: '', [ACTIONS.CONNECT]: '', [ACTIONS.ANDROID_SDK]: '', + [ACTIONS.BUY]: '', + [ACTIONS.SELL]: '', [ACTIONS.BUY_CRYPTO]: '', [ACTIONS.SELL_CRYPTO]: '', METAMASK: 'metamask://', diff --git a/app/core/DeeplinkManager/DeeplinkManager.test.ts b/app/core/DeeplinkManager/DeeplinkManager.test.ts index 9b02346c985..c4fafdba5f2 100644 --- a/app/core/DeeplinkManager/DeeplinkManager.test.ts +++ b/app/core/DeeplinkManager/DeeplinkManager.test.ts @@ -2,13 +2,16 @@ import { NavigationProp, ParamListBase } from '@react-navigation/native'; import DeeplinkManager from './DeeplinkManager'; import handleBrowserUrl from './Handlers/handleBrowserUrl'; import handleEthereumUrl from './Handlers/handleEthereumUrl'; +import handleRampUrl from './Handlers/handleRampUrl'; import switchNetwork from './Handlers/switchNetwork'; import parseDeeplink from './ParseManager/parseDeeplink'; import approveTransaction from './TransactionManager/approveTransaction'; +import { RampType } from '../../reducers/fiatOrders/types'; jest.mock('./TransactionManager/approveTransaction'); jest.mock('./Handlers/handleEthereumUrl'); jest.mock('./Handlers/handleBrowserUrl'); +jest.mock('./Handlers/handleRampUrl'); jest.mock('./ParseManager/parseDeeplink'); jest.mock('./Handlers/switchNetwork'); @@ -96,13 +99,27 @@ describe('DeeplinkManager', () => { }); it('should handle buy crypto action correctly', () => { - deeplinkManager._handleBuyCrypto(); - expect(mockNavigation.navigate).toHaveBeenCalledWith('RampBuy'); + const rampPath = '/example/path?and=params'; + deeplinkManager._handleBuyCrypto(rampPath); + expect(handleRampUrl).toHaveBeenCalledWith( + expect.objectContaining({ + rampPath, + navigation: mockNavigation, + rampType: RampType.BUY, + }), + ); }); it('should handle sell crypto action correctly', () => { - deeplinkManager._handleSellCrypto(); - expect(mockNavigation.navigate).toHaveBeenCalledWith('RampSell'); + const rampPath = '/example/path?and=params'; + deeplinkManager._handleSellCrypto(rampPath); + expect(handleRampUrl).toHaveBeenCalledWith( + expect.objectContaining({ + rampPath, + navigation: mockNavigation, + rampType: RampType.SELL, + }), + ); }); it('should parse deeplinks correctly', () => { diff --git a/app/core/DeeplinkManager/DeeplinkManager.ts b/app/core/DeeplinkManager/DeeplinkManager.ts index ae433b53837..78a8c713f9c 100644 --- a/app/core/DeeplinkManager/DeeplinkManager.ts +++ b/app/core/DeeplinkManager/DeeplinkManager.ts @@ -3,12 +3,13 @@ import { NavigationProp, ParamListBase } from '@react-navigation/native'; import { ParseOutput } from 'eth-url-parser'; import { AnyAction, Dispatch, Store } from 'redux'; -import Routes from '../../constants/navigation/Routes'; import handleBrowserUrl from './Handlers/handleBrowserUrl'; import handleEthereumUrl from './Handlers/handleEthereumUrl'; +import handleRampUrl from './Handlers/handleRampUrl'; import switchNetwork from './Handlers/switchNetwork'; import parseDeeplink from './ParseManager/parseDeeplink'; import approveTransaction from './TransactionManager/approveTransaction'; +import { RampType } from '../../reducers/fiatOrders/types'; class DeeplinkManager { public navigation: NavigationProp; @@ -67,12 +68,20 @@ class DeeplinkManager { }); } - _handleBuyCrypto() { - this.navigation.navigate(Routes.RAMP.BUY); + _handleBuyCrypto(rampPath: string) { + handleRampUrl({ + rampPath, + navigation: this.navigation, + rampType: RampType.BUY, + }); } - _handleSellCrypto() { - this.navigation.navigate(Routes.RAMP.SELL); + _handleSellCrypto(rampPath: string) { + handleRampUrl({ + rampPath, + navigation: this.navigation, + rampType: RampType.SELL, + }); } parse( diff --git a/app/core/DeeplinkManager/Handlers/handleRampUrl.ts b/app/core/DeeplinkManager/Handlers/handleRampUrl.ts new file mode 100644 index 00000000000..183e55c342c --- /dev/null +++ b/app/core/DeeplinkManager/Handlers/handleRampUrl.ts @@ -0,0 +1,24 @@ +import { NavigationProp, ParamListBase } from '@react-navigation/native'; +import { RampType } from '../../../reducers/fiatOrders/types'; +import Routes from '../../../constants/navigation/Routes'; + +interface RampUrlOptions { + rampPath: string; + rampType: RampType; + navigation: NavigationProp; +} + +export default function handleRampUrl({ + rampPath: _rampPath, + rampType, + navigation, +}: RampUrlOptions) { + switch (rampType) { + case RampType.BUY: + navigation.navigate(Routes.RAMP.BUY); + break; + case RampType.SELL: + navigation.navigate(Routes.RAMP.SELL); + break; + } +} diff --git a/app/core/DeeplinkManager/ParseManager/handleMetaMaskDeeplink.ts b/app/core/DeeplinkManager/ParseManager/handleMetaMaskDeeplink.ts index 2c472c468f9..18abe2af891 100644 --- a/app/core/DeeplinkManager/ParseManager/handleMetaMaskDeeplink.ts +++ b/app/core/DeeplinkManager/ParseManager/handleMetaMaskDeeplink.ts @@ -78,10 +78,22 @@ export function handleMetaMaskDeeplink({ .catch((err) => { console.warn(`DeepLinkManager failed to connect`, err); }); - } else if (url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.BUY_CRYPTO}`)) { - instance._handleBuyCrypto(); - } else if (url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.SELL_CRYPTO}`)) { - instance._handleSellCrypto(); + } else if ( + url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.BUY_CRYPTO}`) || + url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.BUY}`) + ) { + const rampPath = url + .replace(`${PREFIXES.METAMASK}${ACTIONS.BUY_CRYPTO}`, '') + .replace(`${PREFIXES.METAMASK}${ACTIONS.BUY}`, ''); + instance._handleBuyCrypto(rampPath); + } else if ( + url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.SELL_CRYPTO}`) || + url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.SELL}`) + ) { + const rampPath = url + .replace(`${PREFIXES.METAMASK}${ACTIONS.SELL_CRYPTO}`, '') + .replace(`${PREFIXES.METAMASK}${ACTIONS.SELL}`, ''); + instance._handleSellCrypto(rampPath); } } diff --git a/app/core/DeeplinkManager/ParseManager/handleUniversalLink.ts b/app/core/DeeplinkManager/ParseManager/handleUniversalLink.ts index 9950ae57a6d..3ee85a84fe0 100644 --- a/app/core/DeeplinkManager/ParseManager/handleUniversalLink.ts +++ b/app/core/DeeplinkManager/ParseManager/handleUniversalLink.ts @@ -89,10 +89,16 @@ function handleUniversalLink({ ); // loops back to open the link with the right protocol instance.parse(deeplinkUrl, { browserCallBack, origin }); - } else if (action === ACTIONS.BUY_CRYPTO) { - instance._handleBuyCrypto(); - } else if (action === ACTIONS.SELL_CRYPTO) { - instance._handleSellCrypto(); + } else if (action === ACTIONS.BUY_CRYPTO || action === ACTIONS.BUY) { + const rampPath = urlObj.href + .replace(`${DEEP_LINK_BASE}/${ACTIONS.BUY_CRYPTO}`, '') + .replace(`${DEEP_LINK_BASE}/${ACTIONS.BUY}`, ''); + instance._handleBuyCrypto(rampPath); + } else if (action === ACTIONS.SELL_CRYPTO || action === ACTIONS.SELL) { + const rampPath = urlObj.href + .replace(`${DEEP_LINK_BASE}/${ACTIONS.SELL_CRYPTO}`, '') + .replace(`${DEEP_LINK_BASE}/${ACTIONS.SELL}`, ''); + instance._handleSellCrypto(rampPath); } else { // If it's our universal link or Apple store deep link don't open it in the browser if ( From 0b83b43bd7ea5fa8c62f80144a341a204a3756ed Mon Sep 17 00:00:00 2001 From: Pedro Pablo Aste Kompen Date: Fri, 5 Apr 2024 16:27:19 -0300 Subject: [PATCH 2/2] feature(ramp): add deeplink folder and handler --- .../UI/Ramp/deeplink/handleRampUrl.test.ts | 34 +++++++++++++++++++ .../UI/Ramp/deeplink/handleRampUrl.ts | 24 +++++++++++++ .../DeeplinkManager/Handlers/handleRampUrl.ts | 25 +------------- 3 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 app/components/UI/Ramp/deeplink/handleRampUrl.test.ts create mode 100644 app/components/UI/Ramp/deeplink/handleRampUrl.ts diff --git a/app/components/UI/Ramp/deeplink/handleRampUrl.test.ts b/app/components/UI/Ramp/deeplink/handleRampUrl.test.ts new file mode 100644 index 00000000000..de832588b1e --- /dev/null +++ b/app/components/UI/Ramp/deeplink/handleRampUrl.test.ts @@ -0,0 +1,34 @@ +import { NavigationProp, ParamListBase } from '@react-navigation/native'; +import { RampType } from '../types'; +import Routes from '../../../../constants/navigation/Routes'; +import handleRampUrl from './handleRampUrl'; + +jest.mock('@react-navigation/native'); + +describe('handleRampUrl', () => { + let navigation: NavigationProp; + + beforeEach(() => { + navigation = { + navigate: jest.fn(), + } as unknown as NavigationProp; + }); + + it('should navigate to BUY route when rampType is BUY', () => { + handleRampUrl({ + rampPath: '/somePath?as=example', + rampType: RampType.BUY, + navigation, + }); + expect(navigation.navigate).toHaveBeenCalledWith(Routes.RAMP.BUY); + }); + + it('should navigate to SELL route when rampType is SELL', () => { + handleRampUrl({ + rampPath: '/somePath?as=example', + rampType: RampType.SELL, + navigation, + }); + expect(navigation.navigate).toHaveBeenCalledWith(Routes.RAMP.SELL); + }); +}); diff --git a/app/components/UI/Ramp/deeplink/handleRampUrl.ts b/app/components/UI/Ramp/deeplink/handleRampUrl.ts new file mode 100644 index 00000000000..58b34f690dc --- /dev/null +++ b/app/components/UI/Ramp/deeplink/handleRampUrl.ts @@ -0,0 +1,24 @@ +import { NavigationProp, ParamListBase } from '@react-navigation/native'; +import { RampType } from '../types'; +import Routes from '../../../../constants/navigation/Routes'; + +interface RampUrlOptions { + rampPath: string; + rampType: RampType; + navigation: NavigationProp; +} + +export default function handleRampUrl({ + rampPath: _rampPath, + rampType, + navigation, +}: RampUrlOptions) { + switch (rampType) { + case RampType.BUY: + navigation.navigate(Routes.RAMP.BUY); + break; + case RampType.SELL: + navigation.navigate(Routes.RAMP.SELL); + break; + } +} diff --git a/app/core/DeeplinkManager/Handlers/handleRampUrl.ts b/app/core/DeeplinkManager/Handlers/handleRampUrl.ts index 183e55c342c..1679714938a 100644 --- a/app/core/DeeplinkManager/Handlers/handleRampUrl.ts +++ b/app/core/DeeplinkManager/Handlers/handleRampUrl.ts @@ -1,24 +1 @@ -import { NavigationProp, ParamListBase } from '@react-navigation/native'; -import { RampType } from '../../../reducers/fiatOrders/types'; -import Routes from '../../../constants/navigation/Routes'; - -interface RampUrlOptions { - rampPath: string; - rampType: RampType; - navigation: NavigationProp; -} - -export default function handleRampUrl({ - rampPath: _rampPath, - rampType, - navigation, -}: RampUrlOptions) { - switch (rampType) { - case RampType.BUY: - navigation.navigate(Routes.RAMP.BUY); - break; - case RampType.SELL: - navigation.navigate(Routes.RAMP.SELL); - break; - } -} +export { default } from '../../../components/UI/Ramp/deeplink/handleRampUrl';