mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 18:00:18 +01:00
Onboarding V2 Privacy settings view (#12253)
* add Set Advanced Privacy Settings onboarding view
This commit is contained in:
parent
78b7f32d97
commit
3d36fbd8ce
@ -1210,6 +1210,9 @@
|
||||
"ipfsGatewayDescription": {
|
||||
"message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution."
|
||||
},
|
||||
"jsDeliver": {
|
||||
"message": "jsDeliver"
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "JSON File",
|
||||
"description": "format for importing an account"
|
||||
@ -1620,6 +1623,14 @@
|
||||
"message": "\"$1\" will close this tab and direct back to $2",
|
||||
"description": "Return the user to the site that initiated onboarding"
|
||||
},
|
||||
"onboardingShowIncomingTransactionsDescription": {
|
||||
"message": "Showing incoming transactions in your wallet relies on communication with $1. Etherscan will have access to your Ethereum address and your IP address. View $2.",
|
||||
"description": "$1 is a clickable link with text defined by the 'etherscan' key. $2 is a clickable link with text defined by the 'privacyMsg' key."
|
||||
},
|
||||
"onboardingUsePhishingDetectionDescription": {
|
||||
"message": "Phishing detection alerts rely on communication with $1. jsDeliver will have access to your IP address. View $2.",
|
||||
"description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link"
|
||||
},
|
||||
"onlyAddTrustedNetworks": {
|
||||
"message": "A malicious network provider can lie about the state of the blockchain and record your network activity. Only add custom networks you trust."
|
||||
},
|
||||
@ -2020,6 +2031,12 @@
|
||||
"separateEachWord": {
|
||||
"message": "Separate each word with a single space"
|
||||
},
|
||||
"setAdvancedPrivacySettings": {
|
||||
"message": "Set advanced privacy settings"
|
||||
},
|
||||
"setAdvancedPrivacySettingsDetails": {
|
||||
"message": "MetaMask uses these trusted third-party services to enhance product usability and safety."
|
||||
},
|
||||
"settings": {
|
||||
"message": "Settings"
|
||||
},
|
||||
@ -2718,6 +2735,9 @@
|
||||
"tryAgain": {
|
||||
"message": "Try again"
|
||||
},
|
||||
"turnOnTokenDetection": {
|
||||
"message": "Turn on Token Detection"
|
||||
},
|
||||
"typePassword": {
|
||||
"message": "Type your MetaMask password"
|
||||
},
|
||||
|
@ -2,6 +2,7 @@
|
||||
@import 'new-account/index';
|
||||
@import 'onboarding-app-header/index';
|
||||
@import 'secure-your-wallet/index';
|
||||
@import 'privacy-settings/index';
|
||||
|
||||
.onboarding-flow {
|
||||
width: 100%;
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
ONBOARDING_UNLOCK_ROUTE,
|
||||
DEFAULT_ROUTE,
|
||||
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
|
||||
ONBOARDING_PRIVACY_SETTINGS_ROUTE,
|
||||
} from '../../helpers/constants/routes';
|
||||
import {
|
||||
getCompletedOnboarding,
|
||||
@ -26,6 +27,7 @@ import NewAccount from './new-account/new-account';
|
||||
import ReviewRecoveryPhrase from './recovery-phrase/review-recovery-phrase';
|
||||
import SecureYourWallet from './secure-your-wallet/secure-your-wallet';
|
||||
import ConfirmRecoveryPhrase from './recovery-phrase/confirm-recovery-phrase';
|
||||
import PrivacySettings from './privacy-settings/privacy-settings';
|
||||
|
||||
export default function OnboardingFlow() {
|
||||
const [seedPhrase, setSeedPhrase] = useState('');
|
||||
@ -41,7 +43,7 @@ export default function OnboardingFlow() {
|
||||
// For ONBOARDING_V2 dev purposes,
|
||||
// Remove when ONBOARDING_V2 dev complete
|
||||
if (process.env.ONBOARDING_V2) {
|
||||
history.push(ONBOARDING_SECURE_YOUR_WALLET_ROUTE);
|
||||
history.push(ONBOARDING_PRIVACY_SETTINGS_ROUTE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -108,6 +110,10 @@ export default function OnboardingFlow() {
|
||||
<Unlock {...routeProps} onSubmit={handleUnlock} />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={ONBOARDING_PRIVACY_SETTINGS_ROUTE}
|
||||
component={PrivacySettings}
|
||||
/>
|
||||
<Route exact path="*" component={OnboardingFlowSwitch} />
|
||||
</Switch>
|
||||
</div>
|
||||
|
50
ui/pages/onboarding-flow/privacy-settings/index.scss
Normal file
50
ui/pages/onboarding-flow/privacy-settings/index.scss
Normal file
@ -0,0 +1,50 @@
|
||||
.privacy-settings {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
max-width: 500px;
|
||||
margin: 24px;
|
||||
}
|
||||
|
||||
&__settings {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
max-width: 620px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
a {
|
||||
color: $Blue-500;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: $Blue-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__setting {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
max-width: 430px;
|
||||
|
||||
&__toggle {
|
||||
margin-left: 42px;
|
||||
}
|
||||
}
|
||||
|
||||
& button {
|
||||
max-width: 50%;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
113
ui/pages/onboarding-flow/privacy-settings/privacy-settings.js
Normal file
113
ui/pages/onboarding-flow/privacy-settings/privacy-settings.js
Normal file
@ -0,0 +1,113 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import Button from '../../../components/ui/button';
|
||||
import Typography from '../../../components/ui/typography';
|
||||
import {
|
||||
FONT_WEIGHT,
|
||||
TYPOGRAPHY,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import {
|
||||
setFeatureFlag,
|
||||
setUsePhishDetect,
|
||||
setUseTokenDetection,
|
||||
} from '../../../store/actions';
|
||||
import { ONBOARDING_PIN_EXTENSION_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { Setting } from './setting';
|
||||
|
||||
export default function PrivacySettings() {
|
||||
const t = useI18nContext();
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
const [usePhishingDetection, setUsePhishingDetection] = useState(true);
|
||||
const [turnOnTokenDetection, setTurnOnTokenDetection] = useState(true);
|
||||
const [showIncomingTransactions, setShowIncomingTransactions] = useState(
|
||||
true,
|
||||
);
|
||||
|
||||
const handleSubmit = () => {
|
||||
dispatch(
|
||||
setFeatureFlag('showIncomingTransactions', showIncomingTransactions),
|
||||
);
|
||||
dispatch(setUsePhishDetect(usePhishingDetection));
|
||||
dispatch(setUseTokenDetection(turnOnTokenDetection));
|
||||
history.push(ONBOARDING_PIN_EXTENSION_ROUTE);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="privacy-settings">
|
||||
<div className="privacy-settings__header">
|
||||
<Typography variant={TYPOGRAPHY.H2} fontWeight={FONT_WEIGHT.BOLD}>
|
||||
{t('setAdvancedPrivacySettings')}
|
||||
</Typography>
|
||||
<Typography variant={TYPOGRAPHY.H4}>
|
||||
{t('setAdvancedPrivacySettingsDetails')}
|
||||
</Typography>
|
||||
</div>
|
||||
<div
|
||||
className="privacy-settings__settings"
|
||||
data-testid="privacy-settings-settings"
|
||||
>
|
||||
<Setting
|
||||
value={showIncomingTransactions}
|
||||
setValue={setShowIncomingTransactions}
|
||||
title={t('showIncomingTransactions')}
|
||||
description={t('onboardingShowIncomingTransactionsDescription', [
|
||||
<a
|
||||
key="etherscan"
|
||||
href="https://etherscan.io/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t('etherscan')}
|
||||
</a>,
|
||||
<a
|
||||
href="https://cn.etherscan.com/privacyPolicy"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
key="privacyMsg"
|
||||
>
|
||||
{t('privacyMsg')}
|
||||
</a>,
|
||||
])}
|
||||
/>
|
||||
<Setting
|
||||
value={usePhishingDetection}
|
||||
setValue={setUsePhishingDetection}
|
||||
title={t('usePhishingDetection')}
|
||||
description={t('onboardingUsePhishingDetectionDescription', [
|
||||
<a
|
||||
href="https://www.jsdelivr.com"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
key="jsDeliver"
|
||||
>
|
||||
{t('jsDeliver')}
|
||||
</a>,
|
||||
<a
|
||||
href="https://www.jsdelivr.com/terms/privacy-policy-jsdelivr-com"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
key="privacyMsg"
|
||||
>
|
||||
{t('privacyMsg')}
|
||||
</a>,
|
||||
])}
|
||||
/>
|
||||
<Setting
|
||||
value={turnOnTokenDetection}
|
||||
setValue={setTurnOnTokenDetection}
|
||||
title={t('turnOnTokenDetection')}
|
||||
description={t('useTokenDetectionDescription')}
|
||||
/>
|
||||
</div>
|
||||
<Button type="primary" rounded onClick={handleSubmit}>
|
||||
{t('done')}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import PrivacySettings from './privacy-settings';
|
||||
|
||||
export default {
|
||||
title: 'Onboarding - Privacy Settings',
|
||||
id: __filename,
|
||||
};
|
||||
|
||||
export const Base = () => {
|
||||
return (
|
||||
<div style={{ maxHeight: '2000px' }}>
|
||||
<PrivacySettings />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import * as actions from '../../../store/actions';
|
||||
import { renderWithProvider } from '../../../../test/jest';
|
||||
import PrivacySettings from './privacy-settings';
|
||||
|
||||
describe('Privacy Settings Onboarding View', () => {
|
||||
const mockStore = {
|
||||
metamask: {
|
||||
provider: {
|
||||
type: 'test',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const store = configureMockStore([thunk])(mockStore);
|
||||
const setFeatureFlagStub = jest.fn();
|
||||
const setUsePhishDetectStub = jest.fn();
|
||||
const setUseTokenDetectionStub = jest.fn();
|
||||
|
||||
actions._setBackgroundConnection({
|
||||
setFeatureFlag: setFeatureFlagStub,
|
||||
setUsePhishDetect: setUsePhishDetectStub,
|
||||
setUseTokenDetection: setUseTokenDetectionStub,
|
||||
});
|
||||
|
||||
it('should update preferences', () => {
|
||||
const { container, getByText } = renderWithProvider(
|
||||
<PrivacySettings />,
|
||||
store,
|
||||
);
|
||||
// All settings are initialized toggled to true
|
||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(0);
|
||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(0);
|
||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(0);
|
||||
const toggles = container.querySelectorAll('input[type=checkbox]');
|
||||
const submitButton = getByText('Done');
|
||||
|
||||
// toggle to false
|
||||
fireEvent.click(toggles[0]);
|
||||
fireEvent.click(toggles[1]);
|
||||
fireEvent.click(toggles[2]);
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(1);
|
||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(1);
|
||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(1);
|
||||
expect(setFeatureFlagStub.mock.calls[0][1]).toStrictEqual(false);
|
||||
expect(setUsePhishDetectStub.mock.calls[0][0]).toStrictEqual(false);
|
||||
expect(setUseTokenDetectionStub.mock.calls[0][0]).toStrictEqual(false);
|
||||
|
||||
// toggle back to true
|
||||
fireEvent.click(toggles[0]);
|
||||
fireEvent.click(toggles[1]);
|
||||
fireEvent.click(toggles[2]);
|
||||
fireEvent.click(submitButton);
|
||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(2);
|
||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(2);
|
||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(2);
|
||||
expect(setFeatureFlagStub.mock.calls[1][1]).toStrictEqual(true);
|
||||
expect(setUsePhishDetectStub.mock.calls[1][0]).toStrictEqual(true);
|
||||
expect(setUseTokenDetectionStub.mock.calls[1][0]).toStrictEqual(true);
|
||||
});
|
||||
});
|
33
ui/pages/onboarding-flow/privacy-settings/setting.js
Normal file
33
ui/pages/onboarding-flow/privacy-settings/setting.js
Normal file
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Box from '../../../components/ui/box';
|
||||
import Typography from '../../../components/ui/typography';
|
||||
import ToggleButton from '../../../components/ui/toggle-button';
|
||||
import {
|
||||
JUSTIFY_CONTENT,
|
||||
TYPOGRAPHY,
|
||||
FONT_WEIGHT,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
|
||||
export const Setting = ({ value, setValue, title, description }) => {
|
||||
return (
|
||||
<Box justifyContent={JUSTIFY_CONTENT.CENTER} margin={3}>
|
||||
<div className="privacy-settings__setting">
|
||||
<Typography variant={TYPOGRAPHY.H5} fontWeight={FONT_WEIGHT.BOLD}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography variant={TYPOGRAPHY.H6}>{description}</Typography>
|
||||
</div>
|
||||
<div className="privacy-settings__setting__toggle">
|
||||
<ToggleButton value={value} onToggle={(val) => setValue(!val)} />
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Setting.propTypes = {
|
||||
value: PropTypes.bool,
|
||||
setValue: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
};
|
Loading…
Reference in New Issue
Block a user