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

refactor(1702-2): auto detect nft component #11364

Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AutoDetectNFTSettings should render correctly 1`] = `
<View
style={
{
"marginTop": 32,
}
}
>
<View
style={
{
"alignItems": "center",
"flexDirection": "row",
}
}
>
<Text
accessibilityRole="text"
style={
{
"color": "#141618",
"flex": 1,
"fontFamily": "EuclidCircularB-Medium",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
Autodetect NFTs
</Text>
<View
style={
{
"marginLeft": 16,
}
}
>
<RCTSwitch
accessibilityRole="switch"
onChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onTintColor="#0376c9"
style={
[
{
"height": 31,
"width": 51,
},
[
{
"alignSelf": "flex-start",
},
{
"backgroundColor": "#bbc0c566",
"borderRadius": 16,
},
],
]
}
testID="nft-opensea-autodetect-mode-section"
thumbTintColor="#ffffff"
tintColor="#bbc0c566"
value={false}
/>
</View>
</View>
<Text
accessibilityRole="text"
style={
{
"color": "#6a737d",
"fontFamily": "EuclidCircularB-Regular",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
Let MetaMask add NFTs you own using third-party services (like OpenSea). Autodetecting NFTs exposes your IP and account address to these services. Enabling this feature could associate your IP address with your Ethereum address and display fake NFTs airdropped by scammers. You can add tokens manually to avoid this risk.
</Text>
</View>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const NFT_AUTO_DETECT_MODE_SECTION =
'nft-opensea-autodetect-mode-section';
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { StyleSheet } from 'react-native';

const createStyles = () =>
StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
},
title: {
flex: 1,
},
switchElement: {
marginLeft: 16,
},
switch: {
alignSelf: 'flex-start',
},
halfSetting: {
marginTop: 16,
},
desc: {
marginTop: 8,
},
setting: {
marginTop: 32,
},
});

export default createStyles;
158 changes: 158 additions & 0 deletions app/components/Views/Settings/AutoDetectNFTSettings/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Third party dependencies
import React from 'react';
import { fireEvent } from '@testing-library/react-native';
import { useNavigation } from '@react-navigation/native';

// External dependencies
import Engine from '../../../../core/Engine';
import renderWithProvider from '../../../../util/test/renderWithProvider';
import { backgroundState } from '../../../../util/test/initial-root-state';

// Internal dependencies
import AutoDetectNFTSettings from './index';
import { NFT_AUTO_DETECT_MODE_SECTION } from './index.constants';

let mockSetDisplayNftMedia: jest.Mock;
let mockSetUseNftDetection: jest.Mock;
let mockAddTraitsToUser: jest.Mock;
let mockTrackEvent: jest.Mock;

beforeEach(() => {
mockSetDisplayNftMedia.mockClear();
mockSetUseNftDetection.mockClear();
mockAddTraitsToUser.mockClear();
mockTrackEvent.mockClear();
});

const mockEngine = Engine;

jest.mock('../../../../core/Engine', () => {
mockSetDisplayNftMedia = jest.fn();
mockSetUseNftDetection = jest.fn();
mockAddTraitsToUser = jest.fn();
mockTrackEvent = jest.fn();
return {
init: () => mockEngine.init({}),
context: {
PreferencesController: {
setDisplayNftMedia: mockSetDisplayNftMedia,
setUseNftDetection: mockSetUseNftDetection,
},
},
};
});

const mockNavigation = {
goBack: jest.fn(),
setOptions: jest.fn(),
};

jest.mock('@react-navigation/native', () => ({
...jest.requireActual('@react-navigation/native'),
useNavigation: jest.fn(() => mockNavigation),
}));

jest.mock('../../../hooks/useMetrics', () => ({
useMetrics: () => ({
addTraitsToUser: mockAddTraitsToUser,
trackEvent: mockTrackEvent,
}),
MetaMetricsEvents: {
NFT_AUTO_DETECTION_ENABLED: 'NFT_AUTO_DETECTION_ENABLED',
},
}));

jest.mock('../../../../util/general', () => ({
timeoutFetch: jest.fn(),
}));

describe('AutoDetectNFTSettings', () => {
beforeEach(() => {
jest.clearAllMocks();
(useNavigation as jest.Mock).mockImplementation(() => mockNavigation);
});

const initialState = {
engine: {
backgroundState: {
...backgroundState,
PreferencesController: {
...backgroundState.PreferencesController,
useTokenDetection: true,
displayNftMedia: false,
useNftDetection: false,
},
},
},
network: {
provider: {
chainId: '1',
},
},
};

it('should render correctly', () => {
const tree = renderWithProvider(<AutoDetectNFTSettings />, {
state: initialState,
});
expect(tree).toMatchSnapshot();
});

describe('NFT Autodetection', () => {
it('should render NFT autodetection switch', () => {
const { getByTestId } = renderWithProvider(<AutoDetectNFTSettings />, {
state: initialState,
});
const autoDetectSwitch = getByTestId(NFT_AUTO_DETECT_MODE_SECTION);
expect(autoDetectSwitch).toBeTruthy();
});

it('should toggle NFT autodetection when switch is pressed', () => {
const { getByTestId } = renderWithProvider(<AutoDetectNFTSettings />, {
state: initialState,
});
const autoDetectSwitch = getByTestId(NFT_AUTO_DETECT_MODE_SECTION);
fireEvent(autoDetectSwitch, 'onValueChange', true);

expect(
Engine.context.PreferencesController.setUseNftDetection,
).toHaveBeenCalledWith(true);
expect(
Engine.context.PreferencesController.setDisplayNftMedia,
).toHaveBeenCalledWith(true);
expect(mockAddTraitsToUser).toHaveBeenCalledWith({
'NFT Autodetection': 'ON',
});
expect(mockTrackEvent).toHaveBeenCalledWith(
'NFT_AUTO_DETECTION_ENABLED',
{
'NFT Autodetection': 'ON',
location: 'app_settings',
},
);
});

it('should not enable display NFT media when autodetection is turned off', () => {
const { getByTestId } = renderWithProvider(<AutoDetectNFTSettings />, {
state: initialState,
});
const autoDetectSwitch = getByTestId(NFT_AUTO_DETECT_MODE_SECTION);
expect(autoDetectSwitch).toBeTruthy();

fireEvent(autoDetectSwitch, 'onValueChange', false);

expect(mockSetUseNftDetection).toHaveBeenCalledWith(false);
expect(mockSetDisplayNftMedia).not.toHaveBeenCalled();
expect(mockAddTraitsToUser).toHaveBeenCalledWith({
'NFT Autodetection': 'OFF',
});
expect(mockTrackEvent).toHaveBeenCalledWith(
'NFT_AUTO_DETECTION_ENABLED',
{
'NFT Autodetection': 'OFF',
location: 'app_settings',
},
);
});
});
});
83 changes: 83 additions & 0 deletions app/components/Views/Settings/AutoDetectNFTSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Third party dependencies
import React, { useCallback } from 'react';
import { View, Switch } from 'react-native';
import { useSelector } from 'react-redux';

// External dependencies
import Engine from '../../../../core/Engine';
import { selectUseNftDetection } from '../../../../selectors/preferencesController';
import { useTheme } from '../../../../util/theme';
import { strings } from '../../../../../locales/i18n';
import { MetaMetricsEvents, useMetrics } from '../../../hooks/useMetrics';
import Text, {
TextVariant,
TextColor,
} from '../../../../component-library/components/Texts/Text';
import { UserProfileProperty } from '../../../../util/metrics/UserSettingsAnalyticsMetaData/UserProfileAnalyticsMetaData.types';

// Internal dependencies
import createStyles from './index.styles';
import { NFT_AUTO_DETECT_MODE_SECTION } from './index.constants';

const AutoDetectNFTSettings = () => {
const { trackEvent, addTraitsToUser } = useMetrics();
const theme = useTheme();
const { colors } = theme;
const styles = createStyles();

const useNftDetection = useSelector(selectUseNftDetection);

const toggleNftAutodetect = useCallback(
(value: boolean) => {
const { PreferencesController } = Engine.context;
if (value) {
PreferencesController.setDisplayNftMedia(value);
}
PreferencesController.setUseNftDetection(value);
const traits = {
[UserProfileProperty.NFT_AUTODETECTION]: value
? UserProfileProperty.ON
: UserProfileProperty.OFF,
};
addTraitsToUser(traits);
trackEvent(MetaMetricsEvents.NFT_AUTO_DETECTION_ENABLED, {
...traits,
location: 'app_settings',
});
},
[addTraitsToUser, trackEvent],
);

return (
<View style={styles.setting}>
<View style={styles.titleContainer}>
<Text variant={TextVariant.BodyLGMedium} style={styles.title}>
{strings('app_settings.nft_autodetect_mode')}
</Text>
<View style={styles.switchElement}>
<Switch
value={useNftDetection}
onValueChange={toggleNftAutodetect}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={theme.brandColors.white}
style={styles.switch}
ios_backgroundColor={colors.border.muted}
testID={NFT_AUTO_DETECT_MODE_SECTION}
/>
</View>
</View>
<Text
variant={TextVariant.BodyMD}
color={TextColor.Alternative}
style={styles.desc}
>
{strings('app_settings.autodetect_nft_desc')}
</Text>
</View>
);
};

export default AutoDetectNFTSettings;
Loading
Loading