Skip to content
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
37 changes: 32 additions & 5 deletions app/components/Views/ActivityView/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import React, { useCallback, useMemo, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { BackHandler, StyleSheet, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';
import { WalletViewSelectorsIDs } from '../Wallet/WalletView.testIds';
Expand All @@ -23,11 +23,13 @@ import { KnownCaipNamespace } from '@metamask/utils';
import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetworkController';
import { selectChainId } from '../../../selectors/networkController';
import { selectNetworkName } from '../../../selectors/networkInfos';
import Routes from '../../../constants/navigation/Routes';
import { useParams } from '../../../util/navigation/navUtils';
import { getNetworkImageSource } from '../../../util/networks';
import { useTheme } from '../../../util/theme';
import { TabsList } from '../../../component-library/components-temp/Tabs';
import { createNetworkManagerNavDetails } from '../../UI/NetworkManager';
import { selectMoneyHomeScreenEnabledFlag } from '../../UI/Money/selectors/featureFlags';
import { selectPerpsEnabledFlag } from '../../UI/Perps';
import { selectPredictEnabledFlag } from '../../UI/Predict/selectors/featureFlags';
import PredictTransactionsView from '../../UI/Predict/views/PredictTransactionsView/PredictTransactionsView';
Expand Down Expand Up @@ -106,6 +108,10 @@ const ActivityView = () => {

const currentNetworkName = getNetworkInfo(0)?.networkName;

const isMoneyHomeScreenEnabled = useSelector(
selectMoneyHomeScreenEnabledFlag,
);

const params = useParams();
const perpsEnabledFlag = useSelector(selectPerpsEnabledFlag);
const isPerpsEnabled = useMemo(
Expand All @@ -123,13 +129,34 @@ const ActivityView = () => {
navigation.navigate(...createNetworkManagerNavDetails({}));
};

// Prevent back button returning to confirmation screen in case that users are redirected after a successful transaction.
const handleNavigateHome = useCallback(() => {
navigation.navigate(Routes.HOME_TABS);
}, [navigation]);

const handleBackPress = useCallback(() => {
if (navigation.canGoBack()) {
if (isMoneyHomeScreenEnabled) {
handleNavigateHome();
} else if (navigation.canGoBack()) {
navigation.goBack();
}
}, [navigation]);
}, [isMoneyHomeScreenEnabled, navigation, handleNavigateHome]);

useEffect(() => {
if (!isMoneyHomeScreenEnabled) return;

const subscription = BackHandler.addEventListener(
'hardwareBackPress',
() => {
handleNavigateHome();
return true;
},
);

return () => subscription.remove();
}, [navigation, isMoneyHomeScreenEnabled, handleNavigateHome]);

const showBackButton = params.showBackButton || false;
const showBackButton = params.showBackButton || isMoneyHomeScreenEnabled;

// Calculate dynamic tab indices based on which tabs are enabled
// Tab order: Transactions (0), Orders (1), Perps (conditional), Predict (conditional)
Expand Down
108 changes: 107 additions & 1 deletion app/components/Views/ActivityView/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React from 'react';
import ActivityView from '.';
import { BackHandler } from 'react-native';
import { backgroundState } from '../../../util/test/initial-root-state';
import renderWithProvider from '../../../util/test/renderWithProvider';
import { createStackNavigator } from '@react-navigation/stack';
import { fireEvent } from '@testing-library/react-native';
import { cleanup, fireEvent } from '@testing-library/react-native';
// eslint-disable-next-line import-x/no-namespace
import * as networkManagerUtils from '../../UI/NetworkManager';
import { useCurrentNetworkInfo } from '../../hooks/useCurrentNetworkInfo';
import { ActivitiesViewSelectorsIDs } from './ActivitiesView.testIds';
import { WalletViewSelectorsIDs } from '../Wallet/WalletView.testIds';
import Routes from '../../../constants/navigation/Routes';

let mockMoneyHomeScreenEnabled = false;
jest.mock('../../UI/Money/selectors/featureFlags', () => ({
selectMoneyHomeScreenEnabledFlag: jest.fn(() => mockMoneyHomeScreenEnabled),
}));

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

let backHandlerSpy: jest.SpyInstance;

const defaultNetworkInfo = {
enabledNetworks: [
{ chainId: '0x1', enabled: true },
Expand Down Expand Up @@ -266,15 +275,26 @@ describe('ActivityView', () => {

beforeEach(() => {
jest.clearAllMocks();
backHandlerSpy = jest
.spyOn(BackHandler, 'addEventListener')
.mockReturnValue({ remove: jest.fn() } as unknown as ReturnType<
typeof BackHandler.addEventListener
>);
mockUseCurrentNetworkInfo.mockReturnValue(defaultNetworkInfo);
mockIsEvmSelected = true;
mockMoneyHomeScreenEnabled = false;
mockPerpsEnabled = false;
mockPredictEnabled = false;
mockAreAllEvmPopularNetworksEnabled = false;
clearRenderedTabs();
mockRoute.params = {};
});

afterEach(() => {
cleanup();
backHandlerSpy.mockRestore();
});

describe('Network Manager Integration', () => {
beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -403,6 +423,80 @@ describe('ActivityView', () => {

expect(mockNavigation.goBack).not.toHaveBeenCalled();
});

it('displays back button when Money home screen flag is enabled without showBackButton param', () => {
mockMoneyHomeScreenEnabled = true;
mockRoute.params = {};

const { getByTestId } = renderComponent(mockInitialState);

expect(getByTestId('activity-view-back-button')).toBeOnTheScreen();
});

it('calls navigation.navigate with HOME_TABS on back button press when Money flag is enabled', () => {
mockMoneyHomeScreenEnabled = true;
mockRoute.params = {};
const { getByTestId } = renderComponent(mockInitialState);

fireEvent.press(getByTestId('activity-view-back-button'));

expect(mockNavigation.navigate).toHaveBeenCalledWith(Routes.HOME_TABS);
expect(mockNavigation.goBack).not.toHaveBeenCalled();
});

it('calls navigation.navigate with HOME_TABS and not goBack when both flag and showBackButton param are true', () => {
mockMoneyHomeScreenEnabled = true;
mockRoute.params = { showBackButton: true };
const { getByTestId } = renderComponent(mockInitialState);

fireEvent.press(getByTestId('activity-view-back-button'));

expect(mockNavigation.navigate).toHaveBeenCalledWith(Routes.HOME_TABS);
expect(mockNavigation.goBack).not.toHaveBeenCalled();
});

it('registers hardwareBackPress handler when Money flag is enabled', () => {
mockMoneyHomeScreenEnabled = true;
mockRoute.params = {};

renderComponent(mockInitialState);

expect(BackHandler.addEventListener).toHaveBeenCalledWith(
'hardwareBackPress',
expect.any(Function),
);
});

it('navigates to HOME_TABS when hardwareBackPress fires with Money flag enabled', () => {
mockMoneyHomeScreenEnabled = true;
mockRoute.params = {};
renderComponent(mockInitialState);
const [[, handler]] = (BackHandler.addEventListener as jest.Mock).mock
.calls;

const result = handler();

expect(mockNavigation.navigate).toHaveBeenCalledWith(Routes.HOME_TABS);
expect(result).toBe(true);
});

it('does not navigate to HOME_TABS on hardwareBackPress when Money flag is disabled', () => {
mockMoneyHomeScreenEnabled = false;
mockRoute.params = {};

renderComponent(mockInitialState);

const hardwareBackPressCalls = (
BackHandler.addEventListener as jest.Mock
).mock.calls.filter(([event]: [string]) => event === 'hardwareBackPress');
hardwareBackPressCalls.forEach(([, handler]: [string, () => boolean]) =>
handler(),
);

expect(mockNavigation.navigate).not.toHaveBeenCalledWith(
Routes.HOME_TABS,
);
});
});

describe('header and SafeAreaView', () => {
Expand Down Expand Up @@ -463,6 +557,18 @@ describe('ActivityView', () => {
queryByTestId(ActivitiesViewSelectorsIDs.HEADER_COMPACT_STANDARD),
).toBeNull();
});

it('renders HeaderCompactStandard when Money home screen flag is enabled', () => {
mockMoneyHomeScreenEnabled = true;
mockRoute.params = {};

const { getByTestId, queryByTestId } = renderComponent(mockInitialState);

expect(
getByTestId(ActivitiesViewSelectorsIDs.HEADER_COMPACT_STANDARD),
).toBeOnTheScreen();
expect(queryByTestId(ActivitiesViewSelectorsIDs.HEADER_ROOT)).toBeNull();
});
});

describe('Perps tab', () => {
Expand Down
5 changes: 1 addition & 4 deletions app/components/Views/Wallet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1061,10 +1061,7 @@ const Wallet = ({
MetaMetricsEvents.ACTIVITY_CLICKED,
).build(),
);
navigation.navigate(Routes.TRANSACTIONS_VIEW, {
screen: Routes.TRANSACTIONS_VIEW,
params: { showBackButton: true },
});
navigation.navigate(Routes.TRANSACTIONS_VIEW);
}, [navigation, trackEvent]);

const getTokenAddedAnalyticsParams = useCallback(
Expand Down
1 change: 1 addition & 0 deletions app/constants/navigation/Routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Routes = {
HOME_TABS: 'Home',
WALLET_VIEW: 'WalletView',
BROWSER_TAB_HOME: 'BrowserTabHome',
BROWSER_VIEW: 'BrowserView',
Expand Down
Loading