Skip to content

Commit 43a99ef

Browse files
authored
fix: MUSD-772 fix earn deposits redirecting to activity view with no way to leave (#29763)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Fixes a regression introduced in #29454 where Earn redirects to the activity view for successful pooled-staking or lending deposits would leave users stranded without a way to exit. This comes as part of a larger change to replace activity with Money in the main navbar. <!-- 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? --> ## **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: Fixes a regression where Earn redirects to the activity view for successful pooled-staking or lending deposits would leave users stranded without a way to exit. ## **Related issues** Fixes: [MUSD-772: Fix deposit redirects for Earn flows leaving users stranded on Activity page](https://consensyssoftware.atlassian.net/browse/MUSD-772) ## **Manual testing steps** ```gherkin Feature: Activity screen navigation when Money Home is enabled Scenario: user accesses activity list from Money Home Given the Money Home feature flag is enabled And user is on the pooled-staking or lending deposit confirmation screen When confirms their transaction Then user is redirected to the activty with And a back button is displayed in the Activity screen header And user can navigate back to Wallet Home without being stranded ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/85bb5c72-978e-4e63-86b4-e35bb35e83da ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/5752d2aa-7f8b-4b32-bec8-b58b5eb2351b ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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** > Changes back-navigation behavior (including Android hardware back handling) for `ActivityView` when the Money Home feature flag is enabled, which could affect user navigation flows if routing assumptions are wrong. Scope is limited and covered by new unit tests around back button and hardware back handling. > > **Overview** > Fixes a regression where users redirected into `ActivityView` (e.g., after successful Earn deposits) could get stuck without a reliable way to exit when the Money Home experience is enabled. > > When `selectMoneyHomeScreenEnabledFlag` is on, `ActivityView` now always shows a back button and routes both header back and Android `hardwareBackPress` to `Routes.HOME_TABS` (instead of returning to the prior stack/confirmation screen). The wallet’s Activity entrypoint no longer passes `showBackButton` params, and `Routes` adds a new `HOME_TABS` route constant. > > Adds/updates `ActivityView` tests to cover Money-flag behavior for header back, hardware back interception, and header variant selection. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e5a0c60. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 66b8511 commit 43a99ef

4 files changed

Lines changed: 141 additions & 10 deletions

File tree

app/components/Views/ActivityView/index.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useFocusEffect, useNavigation } from '@react-navigation/native';
2-
import React, { useCallback, useMemo, useState } from 'react';
3-
import { StyleSheet, View } from 'react-native';
2+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
3+
import { BackHandler, StyleSheet, View } from 'react-native';
44
import { SafeAreaView } from 'react-native-safe-area-context';
55
import { useSelector } from 'react-redux';
66
import { WalletViewSelectorsIDs } from '../Wallet/WalletView.testIds';
@@ -23,11 +23,13 @@ import { KnownCaipNamespace } from '@metamask/utils';
2323
import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetworkController';
2424
import { selectChainId } from '../../../selectors/networkController';
2525
import { selectNetworkName } from '../../../selectors/networkInfos';
26+
import Routes from '../../../constants/navigation/Routes';
2627
import { useParams } from '../../../util/navigation/navUtils';
2728
import { getNetworkImageSource } from '../../../util/networks';
2829
import { useTheme } from '../../../util/theme';
2930
import { TabsList } from '../../../component-library/components-temp/Tabs';
3031
import { createNetworkManagerNavDetails } from '../../UI/NetworkManager';
32+
import { selectMoneyHomeScreenEnabledFlag } from '../../UI/Money/selectors/featureFlags';
3133
import { selectPerpsEnabledFlag } from '../../UI/Perps';
3234
import { selectPredictEnabledFlag } from '../../UI/Predict/selectors/featureFlags';
3335
import PredictTransactionsView from '../../UI/Predict/views/PredictTransactionsView/PredictTransactionsView';
@@ -106,6 +108,10 @@ const ActivityView = () => {
106108

107109
const currentNetworkName = getNetworkInfo(0)?.networkName;
108110

111+
const isMoneyHomeScreenEnabled = useSelector(
112+
selectMoneyHomeScreenEnabledFlag,
113+
);
114+
109115
const params = useParams();
110116
const perpsEnabledFlag = useSelector(selectPerpsEnabledFlag);
111117
const isPerpsEnabled = useMemo(
@@ -123,13 +129,34 @@ const ActivityView = () => {
123129
navigation.navigate(...createNetworkManagerNavDetails({}));
124130
};
125131

132+
// Prevent back button returning to confirmation screen in case that users are redirected after a successful transaction.
133+
const handleNavigateHome = useCallback(() => {
134+
navigation.navigate(Routes.HOME_TABS);
135+
}, [navigation]);
136+
126137
const handleBackPress = useCallback(() => {
127-
if (navigation.canGoBack()) {
138+
if (isMoneyHomeScreenEnabled) {
139+
handleNavigateHome();
140+
} else if (navigation.canGoBack()) {
128141
navigation.goBack();
129142
}
130-
}, [navigation]);
143+
}, [isMoneyHomeScreenEnabled, navigation, handleNavigateHome]);
144+
145+
useEffect(() => {
146+
if (!isMoneyHomeScreenEnabled) return;
147+
148+
const subscription = BackHandler.addEventListener(
149+
'hardwareBackPress',
150+
() => {
151+
handleNavigateHome();
152+
return true;
153+
},
154+
);
155+
156+
return () => subscription.remove();
157+
}, [navigation, isMoneyHomeScreenEnabled, handleNavigateHome]);
131158

132-
const showBackButton = params.showBackButton || false;
159+
const showBackButton = params.showBackButton || isMoneyHomeScreenEnabled;
133160

134161
// Calculate dynamic tab indices based on which tabs are enabled
135162
// Tab order: Transactions (0), Orders (1), Perps (conditional), Predict (conditional)

app/components/Views/ActivityView/index.test.tsx

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import React from 'react';
22
import ActivityView from '.';
3+
import { BackHandler } from 'react-native';
34
import { backgroundState } from '../../../util/test/initial-root-state';
45
import renderWithProvider from '../../../util/test/renderWithProvider';
56
import { createStackNavigator } from '@react-navigation/stack';
6-
import { fireEvent } from '@testing-library/react-native';
7+
import { cleanup, fireEvent } from '@testing-library/react-native';
78
// eslint-disable-next-line import-x/no-namespace
89
import * as networkManagerUtils from '../../UI/NetworkManager';
910
import { useCurrentNetworkInfo } from '../../hooks/useCurrentNetworkInfo';
1011
import { ActivitiesViewSelectorsIDs } from './ActivitiesView.testIds';
1112
import { WalletViewSelectorsIDs } from '../Wallet/WalletView.testIds';
13+
import Routes from '../../../constants/navigation/Routes';
14+
15+
let mockMoneyHomeScreenEnabled = false;
16+
jest.mock('../../UI/Money/selectors/featureFlags', () => ({
17+
selectMoneyHomeScreenEnabledFlag: jest.fn(() => mockMoneyHomeScreenEnabled),
18+
}));
1219

1320
// Mock the Perps feature flag selector - will be controlled per test
1421
let mockPerpsEnabled = false;
@@ -236,6 +243,8 @@ describe('ActivityView', () => {
236243
const mockUseCurrentNetworkInfo =
237244
useCurrentNetworkInfo as jest.MockedFunction<typeof useCurrentNetworkInfo>;
238245

246+
let backHandlerSpy: jest.SpyInstance;
247+
239248
const defaultNetworkInfo = {
240249
enabledNetworks: [
241250
{ chainId: '0x1', enabled: true },
@@ -266,15 +275,26 @@ describe('ActivityView', () => {
266275

267276
beforeEach(() => {
268277
jest.clearAllMocks();
278+
backHandlerSpy = jest
279+
.spyOn(BackHandler, 'addEventListener')
280+
.mockReturnValue({ remove: jest.fn() } as unknown as ReturnType<
281+
typeof BackHandler.addEventListener
282+
>);
269283
mockUseCurrentNetworkInfo.mockReturnValue(defaultNetworkInfo);
270284
mockIsEvmSelected = true;
285+
mockMoneyHomeScreenEnabled = false;
271286
mockPerpsEnabled = false;
272287
mockPredictEnabled = false;
273288
mockAreAllEvmPopularNetworksEnabled = false;
274289
clearRenderedTabs();
275290
mockRoute.params = {};
276291
});
277292

293+
afterEach(() => {
294+
cleanup();
295+
backHandlerSpy.mockRestore();
296+
});
297+
278298
describe('Network Manager Integration', () => {
279299
beforeEach(() => {
280300
jest.clearAllMocks();
@@ -403,6 +423,80 @@ describe('ActivityView', () => {
403423

404424
expect(mockNavigation.goBack).not.toHaveBeenCalled();
405425
});
426+
427+
it('displays back button when Money home screen flag is enabled without showBackButton param', () => {
428+
mockMoneyHomeScreenEnabled = true;
429+
mockRoute.params = {};
430+
431+
const { getByTestId } = renderComponent(mockInitialState);
432+
433+
expect(getByTestId('activity-view-back-button')).toBeOnTheScreen();
434+
});
435+
436+
it('calls navigation.navigate with HOME_TABS on back button press when Money flag is enabled', () => {
437+
mockMoneyHomeScreenEnabled = true;
438+
mockRoute.params = {};
439+
const { getByTestId } = renderComponent(mockInitialState);
440+
441+
fireEvent.press(getByTestId('activity-view-back-button'));
442+
443+
expect(mockNavigation.navigate).toHaveBeenCalledWith(Routes.HOME_TABS);
444+
expect(mockNavigation.goBack).not.toHaveBeenCalled();
445+
});
446+
447+
it('calls navigation.navigate with HOME_TABS and not goBack when both flag and showBackButton param are true', () => {
448+
mockMoneyHomeScreenEnabled = true;
449+
mockRoute.params = { showBackButton: true };
450+
const { getByTestId } = renderComponent(mockInitialState);
451+
452+
fireEvent.press(getByTestId('activity-view-back-button'));
453+
454+
expect(mockNavigation.navigate).toHaveBeenCalledWith(Routes.HOME_TABS);
455+
expect(mockNavigation.goBack).not.toHaveBeenCalled();
456+
});
457+
458+
it('registers hardwareBackPress handler when Money flag is enabled', () => {
459+
mockMoneyHomeScreenEnabled = true;
460+
mockRoute.params = {};
461+
462+
renderComponent(mockInitialState);
463+
464+
expect(BackHandler.addEventListener).toHaveBeenCalledWith(
465+
'hardwareBackPress',
466+
expect.any(Function),
467+
);
468+
});
469+
470+
it('navigates to HOME_TABS when hardwareBackPress fires with Money flag enabled', () => {
471+
mockMoneyHomeScreenEnabled = true;
472+
mockRoute.params = {};
473+
renderComponent(mockInitialState);
474+
const [[, handler]] = (BackHandler.addEventListener as jest.Mock).mock
475+
.calls;
476+
477+
const result = handler();
478+
479+
expect(mockNavigation.navigate).toHaveBeenCalledWith(Routes.HOME_TABS);
480+
expect(result).toBe(true);
481+
});
482+
483+
it('does not navigate to HOME_TABS on hardwareBackPress when Money flag is disabled', () => {
484+
mockMoneyHomeScreenEnabled = false;
485+
mockRoute.params = {};
486+
487+
renderComponent(mockInitialState);
488+
489+
const hardwareBackPressCalls = (
490+
BackHandler.addEventListener as jest.Mock
491+
).mock.calls.filter(([event]: [string]) => event === 'hardwareBackPress');
492+
hardwareBackPressCalls.forEach(([, handler]: [string, () => boolean]) =>
493+
handler(),
494+
);
495+
496+
expect(mockNavigation.navigate).not.toHaveBeenCalledWith(
497+
Routes.HOME_TABS,
498+
);
499+
});
406500
});
407501

408502
describe('header and SafeAreaView', () => {
@@ -463,6 +557,18 @@ describe('ActivityView', () => {
463557
queryByTestId(ActivitiesViewSelectorsIDs.HEADER_COMPACT_STANDARD),
464558
).toBeNull();
465559
});
560+
561+
it('renders HeaderCompactStandard when Money home screen flag is enabled', () => {
562+
mockMoneyHomeScreenEnabled = true;
563+
mockRoute.params = {};
564+
565+
const { getByTestId, queryByTestId } = renderComponent(mockInitialState);
566+
567+
expect(
568+
getByTestId(ActivitiesViewSelectorsIDs.HEADER_COMPACT_STANDARD),
569+
).toBeOnTheScreen();
570+
expect(queryByTestId(ActivitiesViewSelectorsIDs.HEADER_ROOT)).toBeNull();
571+
});
466572
});
467573

468574
describe('Perps tab', () => {

app/components/Views/Wallet/index.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,10 +1061,7 @@ const Wallet = ({
10611061
MetaMetricsEvents.ACTIVITY_CLICKED,
10621062
).build(),
10631063
);
1064-
navigation.navigate(Routes.TRANSACTIONS_VIEW, {
1065-
screen: Routes.TRANSACTIONS_VIEW,
1066-
params: { showBackButton: true },
1067-
});
1064+
navigation.navigate(Routes.TRANSACTIONS_VIEW);
10681065
}, [navigation, trackEvent]);
10691066

10701067
const getTokenAddedAnalyticsParams = useCallback(

app/constants/navigation/Routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const Routes = {
2+
HOME_TABS: 'Home',
23
WALLET_VIEW: 'WalletView',
34
BROWSER_TAB_HOME: 'BrowserTabHome',
45
BROWSER_VIEW: 'BrowserView',

0 commit comments

Comments
 (0)