mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +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": {
|
"ipfsGatewayDescription": {
|
||||||
"message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution."
|
"message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution."
|
||||||
},
|
},
|
||||||
|
"jsDeliver": {
|
||||||
|
"message": "jsDeliver"
|
||||||
|
},
|
||||||
"jsonFile": {
|
"jsonFile": {
|
||||||
"message": "JSON File",
|
"message": "JSON File",
|
||||||
"description": "format for importing an account"
|
"description": "format for importing an account"
|
||||||
@ -1620,6 +1623,14 @@
|
|||||||
"message": "\"$1\" will close this tab and direct back to $2",
|
"message": "\"$1\" will close this tab and direct back to $2",
|
||||||
"description": "Return the user to the site that initiated onboarding"
|
"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": {
|
"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."
|
"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": {
|
"separateEachWord": {
|
||||||
"message": "Separate each word with a single space"
|
"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": {
|
"settings": {
|
||||||
"message": "Settings"
|
"message": "Settings"
|
||||||
},
|
},
|
||||||
@ -2718,6 +2735,9 @@
|
|||||||
"tryAgain": {
|
"tryAgain": {
|
||||||
"message": "Try again"
|
"message": "Try again"
|
||||||
},
|
},
|
||||||
|
"turnOnTokenDetection": {
|
||||||
|
"message": "Turn on Token Detection"
|
||||||
|
},
|
||||||
"typePassword": {
|
"typePassword": {
|
||||||
"message": "Type your MetaMask password"
|
"message": "Type your MetaMask password"
|
||||||
},
|
},
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@import 'new-account/index';
|
@import 'new-account/index';
|
||||||
@import 'onboarding-app-header/index';
|
@import 'onboarding-app-header/index';
|
||||||
@import 'secure-your-wallet/index';
|
@import 'secure-your-wallet/index';
|
||||||
|
@import 'privacy-settings/index';
|
||||||
|
|
||||||
.onboarding-flow {
|
.onboarding-flow {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
ONBOARDING_UNLOCK_ROUTE,
|
ONBOARDING_UNLOCK_ROUTE,
|
||||||
DEFAULT_ROUTE,
|
DEFAULT_ROUTE,
|
||||||
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
|
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
|
||||||
|
ONBOARDING_PRIVACY_SETTINGS_ROUTE,
|
||||||
} from '../../helpers/constants/routes';
|
} from '../../helpers/constants/routes';
|
||||||
import {
|
import {
|
||||||
getCompletedOnboarding,
|
getCompletedOnboarding,
|
||||||
@ -26,6 +27,7 @@ import NewAccount from './new-account/new-account';
|
|||||||
import ReviewRecoveryPhrase from './recovery-phrase/review-recovery-phrase';
|
import ReviewRecoveryPhrase from './recovery-phrase/review-recovery-phrase';
|
||||||
import SecureYourWallet from './secure-your-wallet/secure-your-wallet';
|
import SecureYourWallet from './secure-your-wallet/secure-your-wallet';
|
||||||
import ConfirmRecoveryPhrase from './recovery-phrase/confirm-recovery-phrase';
|
import ConfirmRecoveryPhrase from './recovery-phrase/confirm-recovery-phrase';
|
||||||
|
import PrivacySettings from './privacy-settings/privacy-settings';
|
||||||
|
|
||||||
export default function OnboardingFlow() {
|
export default function OnboardingFlow() {
|
||||||
const [seedPhrase, setSeedPhrase] = useState('');
|
const [seedPhrase, setSeedPhrase] = useState('');
|
||||||
@ -41,7 +43,7 @@ export default function OnboardingFlow() {
|
|||||||
// For ONBOARDING_V2 dev purposes,
|
// For ONBOARDING_V2 dev purposes,
|
||||||
// Remove when ONBOARDING_V2 dev complete
|
// Remove when ONBOARDING_V2 dev complete
|
||||||
if (process.env.ONBOARDING_V2) {
|
if (process.env.ONBOARDING_V2) {
|
||||||
history.push(ONBOARDING_SECURE_YOUR_WALLET_ROUTE);
|
history.push(ONBOARDING_PRIVACY_SETTINGS_ROUTE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +110,10 @@ export default function OnboardingFlow() {
|
|||||||
<Unlock {...routeProps} onSubmit={handleUnlock} />
|
<Unlock {...routeProps} onSubmit={handleUnlock} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path={ONBOARDING_PRIVACY_SETTINGS_ROUTE}
|
||||||
|
component={PrivacySettings}
|
||||||
|
/>
|
||||||
<Route exact path="*" component={OnboardingFlowSwitch} />
|
<Route exact path="*" component={OnboardingFlowSwitch} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</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…
x
Reference in New Issue
Block a user