Skip to content

Commit ba14ec4

Browse files
authored
fix: cash buy button action (#25719)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> The `onBuy` handler drilled down to those components already handles all the logic to navigate correctly, so fallbacks and modals are removed from both the new button layout and the "More" menu. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed flow for "Cash buy X" button on the new token details layout ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I've included tests if applicable - [X] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches buy-call-to-action wiring and removes embedded ramp routing/analytics, which could change purchase entrypoints and event reporting if callers don’t supply `onBuy` correctly. > > **Overview** > Fixes the token details **“Cash buy”** flow by making `onBuy` a required callback and invoking it directly from both the main `TokenDetailsActions` button and the `MoreTokenActionsMenu`, removing internal fallback navigation to fund/ramp flows. > > Cleans up related ramp-specific logic and metrics/tracing in the more-actions menu, and adjusts the token-hide metric to use `asset.chainId` for `chain_id` instead of the selected network chain id. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1646360. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent af8fe0d commit ba14ec4

2 files changed

Lines changed: 10 additions & 149 deletions

File tree

app/components/UI/TokenDetails/components/MoreTokenActionsMenu.tsx

Lines changed: 6 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,13 @@ import { IconName, Box } from '@metamask/design-system-react-native';
88
import ActionListItem from '../../../../component-library/components-temp/ActionListItem';
99
import { strings } from '../../../../../locales/i18n';
1010
import { useMetrics } from '../../../hooks/useMetrics';
11-
import { useRampNavigation } from '../../Ramp/hooks/useRampNavigation';
1211
import useBlockExplorer from '../../../hooks/useBlockExplorer';
13-
import useRampsUnifiedV1Enabled from '../../Ramp/hooks/useRampsUnifiedV1Enabled';
14-
import { useRampsButtonClickData } from '../../Ramp/hooks/useRampsButtonClickData';
1512
import Routes from '../../../../constants/navigation/Routes';
1613
import Engine from '../../../../core/Engine';
1714
import NotificationManager from '../../../../core/NotificationManager';
1815
import { selectTokenList } from '../../../../selectors/tokenListController';
19-
import { selectChainId } from '../../../../selectors/networkController';
2016
import { getDecimalChainId } from '../../../../util/networks';
21-
import { getDetectedGeolocation } from '../../../../reducers/fiatOrders';
2217
import { MetaMetricsEvents } from '../../../../core/Analytics';
23-
import { trace, TraceName } from '../../../../util/trace';
24-
import { RampType } from '../../../../reducers/fiatOrders/types';
2518
import { WalletActionsBottomSheetSelectorsIDs } from '../../../Views/WalletActions/WalletActionsBottomSheet.testIds';
2619
import Logger from '../../../../util/Logger';
2720
import { Hex } from '@metamask/utils';
@@ -34,7 +27,7 @@ export interface MoreTokenActionsMenuParams {
3427
isBuyable: boolean;
3528
isNativeCurrency: boolean;
3629
asset: TokenI;
37-
onBuy?: () => void;
30+
onBuy: () => void;
3831
onReceive?: () => void;
3932
}
4033

@@ -65,17 +58,12 @@ const MoreTokenActionsMenu = () => {
6558
isBuyable,
6659
isNativeCurrency,
6760
asset,
68-
onBuy: customOnBuy,
61+
onBuy,
6962
onReceive,
7063
} = route.params;
7164

7265
const { trackEvent, createEventBuilder } = useMetrics();
73-
const { goToBuy, goToAggregator } = useRampNavigation();
74-
const rampUnifiedV1Enabled = useRampsUnifiedV1Enabled();
75-
const rampsButtonClickData = useRampsButtonClickData();
76-
const rampGeodetectedRegion = useSelector(getDetectedGeolocation);
7766
const tokenList = useSelector(selectTokenList);
78-
const chainId = useSelector(selectChainId);
7967
const explorer = useBlockExplorer(asset.chainId);
8068

8169
const closeBottomSheetAndNavigate = useCallback(
@@ -101,99 +89,9 @@ const MoreTokenActionsMenu = () => {
10189
[closeBottomSheetAndNavigate, navigation],
10290
);
10391

104-
const getChainIdForAsset = useCallback(() => {
105-
if (asset.chainId) {
106-
if (typeof asset.chainId === 'string' && asset.chainId.startsWith('0x')) {
107-
const parsed = parseInt(asset.chainId, 16);
108-
return isNaN(parsed) ? getDecimalChainId(chainId) : parsed;
109-
}
110-
const parsed = parseInt(asset.chainId, 10);
111-
return isNaN(parsed) ? getDecimalChainId(chainId) : parsed;
112-
}
113-
return getDecimalChainId(chainId);
114-
}, [asset.chainId, chainId]);
115-
116-
// Fund action handlers (same as FundActionMenu)
117-
const handleBuyUnified = useCallback(() => {
118-
closeBottomSheetAndNavigate(() => {
119-
if (customOnBuy) {
120-
customOnBuy();
121-
} else {
122-
goToBuy({ assetId: asset.address });
123-
}
124-
});
125-
126-
if (!customOnBuy) {
127-
trackEvent(
128-
createEventBuilder(MetaMetricsEvents.RAMPS_BUTTON_CLICKED)
129-
.addProperties({
130-
text: 'Buy',
131-
location: 'MoreTokenActionsMenu',
132-
chain_id_destination: getChainIdForAsset(),
133-
ramp_type: 'UNIFIED_BUY',
134-
region: rampGeodetectedRegion,
135-
ramp_routing: rampsButtonClickData.ramp_routing,
136-
is_authenticated: rampsButtonClickData.is_authenticated,
137-
preferred_provider: rampsButtonClickData.preferred_provider,
138-
order_count: rampsButtonClickData.order_count,
139-
})
140-
.build(),
141-
);
142-
}
143-
}, [
144-
closeBottomSheetAndNavigate,
145-
customOnBuy,
146-
goToBuy,
147-
asset.address,
148-
trackEvent,
149-
createEventBuilder,
150-
getChainIdForAsset,
151-
rampGeodetectedRegion,
152-
rampsButtonClickData,
153-
]);
154-
15592
const handleBuy = useCallback(() => {
156-
closeBottomSheetAndNavigate(() => {
157-
if (customOnBuy) {
158-
customOnBuy();
159-
} else {
160-
goToAggregator({ assetId: asset.address });
161-
}
162-
});
163-
164-
if (!customOnBuy) {
165-
trackEvent(
166-
createEventBuilder(MetaMetricsEvents.RAMPS_BUTTON_CLICKED)
167-
.addProperties({
168-
text: 'Buy',
169-
location: 'MoreTokenActionsMenu',
170-
chain_id_destination: getChainIdForAsset(),
171-
ramp_type: 'BUY',
172-
region: rampGeodetectedRegion,
173-
ramp_routing: rampsButtonClickData.ramp_routing,
174-
is_authenticated: rampsButtonClickData.is_authenticated,
175-
preferred_provider: rampsButtonClickData.preferred_provider,
176-
order_count: rampsButtonClickData.order_count,
177-
})
178-
.build(),
179-
);
180-
181-
trace({
182-
name: TraceName.LoadRampExperience,
183-
tags: { rampType: RampType.BUY },
184-
});
185-
}
186-
}, [
187-
closeBottomSheetAndNavigate,
188-
customOnBuy,
189-
goToAggregator,
190-
asset.address,
191-
trackEvent,
192-
createEventBuilder,
193-
getChainIdForAsset,
194-
rampGeodetectedRegion,
195-
rampsButtonClickData,
196-
]);
93+
closeBottomSheetAndNavigate(onBuy);
94+
}, [closeBottomSheetAndNavigate, onBuy]);
19795

19896
const handleReceive = useCallback(() => {
19997
closeBottomSheetAndNavigate(() => {
@@ -251,7 +149,7 @@ const MoreTokenActionsMenu = () => {
251149
token_standard: 'ERC20',
252150
asset_type: 'token',
253151
tokens: [`${tokenSymbol} - ${asset.address}`],
254-
chain_id: getDecimalChainId(chainId),
152+
chain_id: getDecimalChainId(asset.chainId),
255153
})
256154
.build(),
257155
);
@@ -270,7 +168,6 @@ const MoreTokenActionsMenu = () => {
270168
tokenList,
271169
trackEvent,
272170
createEventBuilder,
273-
chainId,
274171
]);
275172

276173
const actionConfigs: ActionConfig[] = useMemo(() => {
@@ -297,7 +194,7 @@ const MoreTokenActionsMenu = () => {
297194
iconName: IconName.AttachMoney,
298195
testID: WalletActionsBottomSheetSelectorsIDs.BUY_BUTTON,
299196
isVisible: true,
300-
onPress: rampUnifiedV1Enabled ? handleBuyUnified : handleBuy,
197+
onPress: handleBuy,
301198
});
302199
}
303200

@@ -334,10 +231,8 @@ const MoreTokenActionsMenu = () => {
334231
asset.chainId,
335232
asset.symbol,
336233
explorer,
337-
rampUnifiedV1Enabled,
338234
onReceive,
339235
handleReceive,
340-
handleBuyUnified,
341236
handleBuy,
342237
handleViewOnBlockExplorer,
343238
handleRemoveToken,

app/components/UI/TokenDetails/components/TokenDetailsActions.tsx

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@ import { TokenOverviewSelectorsIDs } from '../../AssetOverview/TokenOverview.tes
1010
import { useSelector } from 'react-redux';
1111
import { selectCanSignTransactions } from '../../../../selectors/accountsController';
1212
import Routes from '../../../../constants/navigation/Routes';
13-
import { useMetrics } from '../../../hooks/useMetrics';
14-
import {
15-
trackActionButtonClick,
16-
ActionButtonType,
17-
ActionLocation,
18-
ActionPosition,
19-
} from '../../../../util/analytics/actionButtonTracking';
2013
import { TokenI } from '../../Tokens/types';
2114

2215
// Height of MainActionButton: paddingVertical (16 * 2) + Icon (24px) + label marginTop (2) + label lineHeight (~16)
@@ -45,7 +38,7 @@ export interface TokenDetailsActionsProps {
4538
isBuyable: boolean;
4639
isNativeCurrency: boolean;
4740
token: TokenI;
48-
onBuy?: () => void;
41+
onBuy: () => void;
4942
onLong?: () => void;
5043
onShort?: () => void;
5144
onSend: () => void;
@@ -93,7 +86,6 @@ export const TokenDetailsActions: React.FC<TokenDetailsActionsProps> = ({
9386
const canSignTransactions = useSelector(selectCanSignTransactions);
9487
const navigation = useNavigation();
9588
const { navigate } = navigation;
96-
const { trackEvent, createEventBuilder } = useMetrics();
9789

9890
// Prevent rapid navigation clicks - locks all buttons during navigation
9991
const navigationLockRef = useRef(false);
@@ -121,33 +113,8 @@ export const TokenDetailsActions: React.FC<TokenDetailsActionsProps> = ({
121113
}, []);
122114

123115
const handleBuyPress = useCallback(() => {
124-
withNavigationLock(() => {
125-
trackActionButtonClick(trackEvent, createEventBuilder, {
126-
action_name: ActionButtonType.BUY,
127-
action_position: ActionPosition.FIRST_POSITION,
128-
button_label: strings('asset_overview.cash_buy_button'),
129-
location: ActionLocation.HOME,
130-
});
131-
132-
navigate(Routes.MODAL.ROOT_MODAL_FLOW, {
133-
screen: Routes.MODAL.FUND_ACTION_MENU,
134-
params: {
135-
onBuy,
136-
asset: {
137-
address: token.address,
138-
chainId: token.chainId,
139-
},
140-
},
141-
});
142-
});
143-
}, [
144-
withNavigationLock,
145-
trackEvent,
146-
createEventBuilder,
147-
navigate,
148-
onBuy,
149-
token,
150-
]);
116+
withNavigationLock(onBuy);
117+
}, [withNavigationLock, onBuy]);
151118

152119
const handleLongPress = useCallback(() => {
153120
withNavigationLock(() => {
@@ -213,7 +180,7 @@ export const TokenDetailsActions: React.FC<TokenDetailsActionsProps> = ({
213180
iconName: IconName.AttachMoney,
214181
label: strings('asset_overview.cash_buy_button'),
215182
onPress: handleBuyPress,
216-
isDisabled: !onBuy,
183+
isDisabled: false,
217184
testID: TokenOverviewSelectorsIDs.BUY_BUTTON,
218185
});
219186
}
@@ -322,7 +289,6 @@ export const TokenDetailsActions: React.FC<TokenDetailsActionsProps> = ({
322289
handleReceivePress,
323290
handleMorePress,
324291
canSignTransactions,
325-
onBuy,
326292
onLong,
327293
onShort,
328294
]);

0 commit comments

Comments
 (0)