1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

Updating Terms of Use, Adding popover and onboarding flow check (#18221)

* WIP commit

* Moving copy out of messages.json, styling changes

* handling scroll button click and disable logic

* moving scrollButton up to popover component, adding logic for accepting terms of use in popover and onboarding flows

* adding terms of use to e2e wallet creation/import

* adjusting failing unit test

* fixing QR code e2e

* updating welcome test

* setting app state in fixtures

* Update app/scripts/controllers/app-state.js

removing console log

Co-authored-by: Nidhi Kumari <nidhi.kumari@consensys.net>

* Update ui/components/app/terms-of-use-popup/terms-of-use-popup.stories.js

adding args to ToU popup storybook

Co-authored-by: Nidhi Kumari <nidhi.kumari@consensys.net>

* Update ui/components/app/terms-of-use-popup/terms-of-use-popup.js

Co-authored-by: Nidhi Kumari <nidhi.kumari@consensys.net>

* updating DS components in terms of use

* popover styling changes

* adding metametrics tracking

* editing scrollbutton behavior

* adding unit test

* code fencing

---------

Co-authored-by: Nidhi Kumari <nidhi.kumari@consensys.net>
This commit is contained in:
vthomas13 2023-04-14 12:51:13 -04:00 committed by GitHub
parent 26db0aee46
commit 40e4a3653f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1488 additions and 39 deletions

View File

@ -109,6 +109,9 @@
"about": {
"message": "About"
},
"accept": {
"message": "Accept"
},
"acceptTermsOfUse": {
"message": "I have read and agree to the $1",
"description": "$1 is the `terms` message"
@ -305,6 +308,10 @@
"advancedPriorityFeeToolTip": {
"message": "Priority fee (aka “miner tip”) goes directly to miners and incentivizes them to prioritize your transaction."
},
"agreeTermsOfUse": {
"message": "I agree to Metamask's $1",
"description": "$1 is the `terms` link"
},
"airgapVault": {
"message": "AirGap Vault"
},
@ -4310,6 +4317,15 @@
"termsOfUse": {
"message": "terms of use"
},
"termsOfUseAgreeText": {
"message": " I agree to the Terms of Use, which apply to my use of MetaMask and all of its features"
},
"termsOfUseFooterText": {
"message": "Please scroll to read all sections"
},
"termsOfUseTitle": {
"message": "Our Terms of Use have updated"
},
"testNetworks": {
"message": "Test networks"
},

View File

@ -172,6 +172,17 @@ export default class AppStateController extends EventEmitter {
});
}
/**
* Record the timestamp of the last time the user has acceoted the terms of use
*
* @param {number} lastAgreed - timestamp when user last accepted the terms of use
*/
setTermsOfUseLastAgreed(lastAgreed) {
this.store.updateState({
termsOfUseLastAgreed: lastAgreed,
});
}
/**
* Record the timestamp of the last time the user has seen the outdated browser warning
*

View File

@ -2032,6 +2032,8 @@ export default class MetamaskController extends EventEmitter {
appStateController.setRecoveryPhraseReminderLastShown.bind(
appStateController,
),
setTermsOfUseLastAgreed:
appStateController.setTermsOfUseLastAgreed.bind(appStateController),
setOutdatedBrowserWarningLastShown:
appStateController.setOutdatedBrowserWarningLastShown.bind(
appStateController,

View File

@ -510,6 +510,8 @@ export enum MetaMetricsEventName {
SignatureFailed = 'Signature Failed',
SignatureRejected = 'Signature Rejected',
SignatureRequested = 'Signature Requested',
TermsOfUseShown = 'Terms of Use Shown',
TermsOfUseAccepted = 'Terms of Use Accepted',
TokenImportButtonClicked = 'Import Token Button Clicked',
TokenScreenOpened = 'Token Screen Opened',
SupportLinkClicked = 'Support Link Clicked',

View File

@ -0,0 +1 @@
export const TERMS_OF_USE_LAST_UPDATED = '2023-03-25';

View File

@ -140,6 +140,7 @@ function defaultFixture() {
browserEnvironment: {},
nftsDropdownState: {},
connectedStatusPopoverHasBeenShown: true,
termsOfUseLastAgreed: 86400000000000,
defaultHomeActiveTabName: null,
fullScreenGasPollTokens: [],
notificationGasPollTokens: [],

View File

@ -222,6 +222,9 @@ const getWindowHandles = async (driver, handlesCount) => {
};
const importSRPOnboardingFlow = async (driver, seedPhrase, password) => {
// agree to terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-import-wallet"]');
@ -262,6 +265,9 @@ const completeImportSRPOnboardingFlowWordByWord = async (
seedPhrase,
password,
) => {
// agree to terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-import-wallet"]');
@ -293,6 +299,9 @@ const completeImportSRPOnboardingFlowWordByWord = async (
};
const completeCreateNewWalletOnboardingFlow = async (driver, password) => {
// agree to terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-create-wallet"]');
@ -342,6 +351,9 @@ const completeCreateNewWalletOnboardingFlow = async (driver, password) => {
};
const importWrongSRPOnboardingFlow = async (driver, seedPhrase) => {
// agree to terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-import-wallet"]');

View File

@ -84,6 +84,7 @@ describe('MetaMask', function () {
describe('Going through the first time flow', function () {
it('clicks the "Create New Wallet" button on the welcome screen', async function () {
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
await driver.clickElement('[data-testid="onboarding-create-wallet"]');
});

View File

@ -29,6 +29,8 @@ describe('Incremental Security', function () {
},
async ({ driver }) => {
await driver.navigate();
// agree to terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-create-wallet"]');

View File

@ -15,6 +15,8 @@ describe('MetaMask Responsive UI', function () {
},
async ({ driver }) => {
await driver.navigate();
// agree to terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-create-wallet"]');

View File

@ -108,6 +108,9 @@ describe('MetaMask onboarding', function () {
async ({ driver }) => {
await driver.navigate();
// accept terms of use
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
// welcome
await driver.clickElement('[data-testid="onboarding-import-wallet"]');
@ -145,6 +148,7 @@ describe('MetaMask onboarding', function () {
async ({ driver }) => {
await driver.navigate();
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
await driver.clickElement('[data-testid="onboarding-create-wallet"]');
// metrics
@ -208,6 +212,7 @@ describe('MetaMask onboarding', function () {
async ({ driver }) => {
await driver.navigate();
await driver.clickElement('[data-testid="onboarding-terms-checkbox"]');
await driver.clickElement('[data-testid="onboarding-create-wallet"]');
// metrics

View File

@ -83,6 +83,7 @@
@import 'transaction-status-label/index';
@import 'wallet-overview/index';
@import 'whats-new-popup/index';
@import 'terms-of-use-popup/index';
@import 'loading-network-screen/index';
@import 'transaction-decoding/index';
@import 'advanced-gas-fee-popover/index';

View File

@ -0,0 +1 @@
export { default } from './terms-of-use-popup';

View File

@ -0,0 +1,30 @@
.popover-wrap.terms-of-use__popover {
.terms-of-use {
&__terms-list {
list-style: decimal none outside;
}
&__footer-text {
align-self: center;
}
}
.popover-header {
&__title {
margin-bottom: 0;
}
}
.popover-footer {
border-top: none;
}
@include screen-sm-min {
max-height: 750px;
width: 500px;
}
@include screen-sm-max {
max-height: 568px;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
import React from 'react';
import TermsOfUsePopup from '.';
export default {
title: 'Components/App/TermsOfUsePopup',
component: TermsOfUsePopup,
argTypes: {
onAccept: {
action: 'onAccept',
},
},
};
export const DefaultStory = (args) => <TermsOfUsePopup {...args} />;
DefaultStory.storyName = 'Default';

View File

@ -0,0 +1,48 @@
import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/jest';
import configureStore from '../../../store/store';
import mockState from '../../../../test/data/mock-state.json';
import TermsOfUsePopup from './terms-of-use-popup';
const render = () => {
const store = configureStore({
metamask: {
...mockState.metamask,
},
});
const onAccept = jest.fn();
return renderWithProvider(<TermsOfUsePopup onAccept={onAccept} />, store);
};
describe('TermsOfUsePopup', () => {
beforeEach(() => {
const mockIntersectionObserver = jest.fn();
mockIntersectionObserver.mockReturnValue({
observe: () => null,
unobserve: () => null,
disconnect: () => null,
});
window.IntersectionObserver = mockIntersectionObserver;
});
it('renders TermsOfUse component and shows Terms of Use text', () => {
render();
expect(
screen.getByText('Our Terms of Use have updated'),
).toBeInTheDocument();
});
it('scrolls down when handleScrollDownClick is called', () => {
render();
const mockScrollIntoView = jest.fn();
window.HTMLElement.prototype.scrollIntoView = mockScrollIntoView;
const button = document.querySelector(
"[data-testid='popover-scroll-button']",
);
fireEvent.click(button);
expect(mockScrollIntoView).toHaveBeenCalledWith({
behavior: 'smooth',
});
});
});

View File

@ -66,28 +66,6 @@
height: 1px;
width: 100%;
}
&__scroll-button {
position: absolute;
bottom: 12px;
right: 12px;
height: 32px;
width: 32px;
border-radius: 14px;
border: 1px solid var(--color-border-default);
background: var(--color-background-alternative);
color: var(--color-icon-default);
z-index: 201;
cursor: pointer;
opacity: 0.8;
display: flex;
justify-content: center;
align-items: center;
&:hover {
opacity: 1;
}
}
}
.popover-wrap.whats-new-popup__popover {

View File

@ -62,6 +62,26 @@
}
}
&-scroll-button {
position: absolute;
bottom: 12px;
right: 12px;
height: 32px;
width: 32px;
border-radius: 50%;
border: 1px solid var(--color-primary-default);
z-index: 201;
cursor: pointer;
opacity: 1;
display: flex;
justify-content: center;
align-items: center;
&:hover {
opacity: 1;
}
}
&-arrow {
width: 22px;
height: 22px;

View File

@ -127,6 +127,16 @@ const Popover = ({
className={classnames('popover-wrap', className)}
ref={popoverRef}
>
{showArrow ? <div className="popover-arrow" /> : null}
{showHeader && <Header />}
{children ? (
<Box
className={classnames('popover-content', contentClassName)}
{...{ ...defaultContentProps, ...contentProps }}
>
{children}
</Box>
) : null}
{showScrollDown ? (
<Box
display={DISPLAY.FLEX}
@ -136,8 +146,9 @@ const Popover = ({
backgroundColor={BackgroundColor.backgroundDefault}
color={Color.iconDefault}
onClick={onScrollDownButtonClick}
className="whats-new-popup__scroll-button"
data-testid="whats-new-popup-scroll-button"
className="popover-scroll-button"
style={{ bottom: footer ? '140px' : '12px' }}
data-testid="popover-scroll-button"
>
<Icon
name={ICON_NAMES.ARROW_DOWN}
@ -147,16 +158,6 @@ const Popover = ({
/>
</Box>
) : null}
{showArrow ? <div className="popover-arrow" /> : null}
{showHeader && <Header />}
{children ? (
<Box
className={classnames('popover-content', contentClassName)}
{...{ ...defaultContentProps, ...contentProps }}
>
{children}
</Box>
) : null}
{footer ? (
<Box
className={classnames('popover-footer', footerClassName)}

View File

@ -47,6 +47,7 @@ interface AppState {
openMetaMaskTabs: Record<string, boolean>; // openMetamaskTabsIDs[tab.id]): true/false
currentWindowTab: Record<string, any>; // tabs.tab https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/Tab
showWhatsNewPopup: boolean;
showTermsOfUsePopup: boolean;
singleExceptions: {
testKey: string | null;
};
@ -109,6 +110,7 @@ const initialState: AppState = {
openMetaMaskTabs: {},
currentWindowTab: {},
showWhatsNewPopup: true,
showTermsOfUsePopup: true,
singleExceptions: {
testKey: null,
},

View File

@ -2,12 +2,14 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { Redirect, Route } from 'react-router-dom';
///: BEGIN:ONLY_INCLUDE_IN(main)
// eslint-disable-next-line import/no-duplicates
import { MetaMetricsContextProp } from '../../../shared/constants/metametrics';
///: END:ONLY_INCLUDE_IN
import {
MetaMetricsContextProp,
MetaMetricsEventCategory,
MetaMetricsEventName,
// eslint-disable-next-line import/no-duplicates
} from '../../../shared/constants/metametrics';
///: END:ONLY_INCLUDE_IN
import AssetList from '../../components/app/asset-list';
import NftsTab from '../../components/app/nfts-tab';
import HomeNotification from '../../components/app/home-notification';
@ -22,6 +24,7 @@ import ConnectedAccounts from '../connected-accounts';
import { Tabs, Tab } from '../../components/ui/tabs';
import { EthOverview } from '../../components/app/wallet-overview';
import WhatsNewPopup from '../../components/app/whats-new-popup';
import TermsOfUsePopup from '../../components/app/terms-of-use-popup';
import RecoveryPhraseReminder from '../../components/app/recovery-phrase-reminder';
import ActionableMessage from '../../components/ui/actionable-message/actionable-message';
import {
@ -111,6 +114,7 @@ export default class Home extends PureComponent {
infuraBlocked: PropTypes.bool.isRequired,
showWhatsNewPopup: PropTypes.bool.isRequired,
hideWhatsNewPopup: PropTypes.func.isRequired,
showTermsOfUsePopup: PropTypes.bool.isRequired,
announcementsToShow: PropTypes.bool.isRequired,
///: BEGIN:ONLY_INCLUDE_IN(flask)
errorsToShow: PropTypes.object.isRequired,
@ -120,6 +124,7 @@ export default class Home extends PureComponent {
showRecoveryPhraseReminder: PropTypes.bool.isRequired,
setRecoveryPhraseReminderHasBeenShown: PropTypes.func.isRequired,
setRecoveryPhraseReminderLastShown: PropTypes.func.isRequired,
setTermsOfUseLastAgreed: PropTypes.func.isRequired,
showOutdatedBrowserWarning: PropTypes.bool.isRequired,
setOutdatedBrowserWarningLastShown: PropTypes.func.isRequired,
seedPhraseBackedUp: (props) => {
@ -243,6 +248,18 @@ export default class Home extends PureComponent {
setRecoveryPhraseReminderLastShown(new Date().getTime());
};
onAcceptTermsOfUse = () => {
const { setTermsOfUseLastAgreed } = this.props;
setTermsOfUseLastAgreed(new Date().getTime());
this.context.trackEvent({
category: MetaMetricsEventCategory.Onboarding,
event: MetaMetricsEventName.TermsOfUseAccepted,
properties: {
location: 'Terms Of Use Popover',
},
});
};
onOutdatedBrowserWarningClose = () => {
const { setOutdatedBrowserWarningLastShown } = this.props;
setOutdatedBrowserWarningLastShown(new Date().getTime());
@ -600,6 +617,7 @@ export default class Home extends PureComponent {
announcementsToShow,
showWhatsNewPopup,
hideWhatsNewPopup,
showTermsOfUsePopup,
seedPhraseBackedUp,
showRecoveryPhraseReminder,
firstTimeFlowType,
@ -621,6 +639,10 @@ export default class Home extends PureComponent {
showWhatsNewPopup &&
!process.env.IN_TEST &&
!newNetworkAddedConfigurationId;
const showTermsOfUse =
completedOnboarding && !onboardedInThisUISession && showTermsOfUsePopup;
return (
<div className="main-container">
<Route path={CONNECTED_ROUTE} component={ConnectedSites} exact />
@ -637,6 +659,9 @@ export default class Home extends PureComponent {
onConfirm={this.onRecoveryPhraseReminderClose}
/>
) : null}
{showTermsOfUse ? (
<TermsOfUsePopup onAccept={this.onAcceptTermsOfUse} />
) : null}
{isPopup && !connectedStatusPopoverHasBeenShown
? this.renderPopover()
: null}

View File

@ -17,6 +17,7 @@ import {
getShowWhatsNewPopup,
getSortedAnnouncementsToShow,
getShowRecoveryPhraseReminder,
getShowTermsOfUse,
getShowOutdatedBrowserWarning,
getNewNetworkAdded,
hasUnsignedQRHardwareTransaction,
@ -35,6 +36,7 @@ import {
setAlertEnabledness,
setRecoveryPhraseReminderHasBeenShown,
setRecoveryPhraseReminderLastShown,
setTermsOfUseLastAgreed,
setOutdatedBrowserWarningLastShown,
setNewNetworkAdded,
setNewNftAddedMessage,
@ -136,6 +138,7 @@ const mapStateToProps = (state) => {
///: END:ONLY_INCLUDE_IN
showWhatsNewPopup: getShowWhatsNewPopup(state),
showRecoveryPhraseReminder: getShowRecoveryPhraseReminder(state),
showTermsOfUsePopup: getShowTermsOfUse(state),
showOutdatedBrowserWarning:
getIsBrowserDeprecated() && getShowOutdatedBrowserWarning(state),
seedPhraseBackedUp,
@ -166,6 +169,9 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setRecoveryPhraseReminderHasBeenShown()),
setRecoveryPhraseReminderLastShown: (lastShown) =>
dispatch(setRecoveryPhraseReminderLastShown(lastShown)),
setTermsOfUseLastAgreed: (lastAgreed) => {
dispatch(setTermsOfUseLastAgreed(lastAgreed));
},
setOutdatedBrowserWarningLastShown: (lastShown) => {
dispatch(setOutdatedBrowserWarningLastShown(lastShown));
},

View File

@ -51,4 +51,9 @@
margin-bottom: 24px;
}
}
&__terms-checkbox {
margin: 0;
align-self: flex-start;
}
}

View File

@ -6,10 +6,13 @@ import { Carousel } from 'react-responsive-carousel';
import Mascot from '../../../components/ui/mascot';
import Button from '../../../components/ui/button';
import { Text } from '../../../components/component-library';
import CheckBox from '../../../components/ui/check-box';
import Box from '../../../components/ui/box';
import {
FONT_WEIGHT,
TEXT_ALIGN,
TextVariant,
AlignItems,
} from '../../../helpers/constants/design-system';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { MetaMetricsContext } from '../../../contexts/metametrics';
@ -17,7 +20,10 @@ import {
MetaMetricsEventCategory,
MetaMetricsEventName,
} from '../../../../shared/constants/metametrics';
import { setFirstTimeFlowType } from '../../../store/actions';
import {
setFirstTimeFlowType,
setTermsOfUseLastAgreed,
} from '../../../store/actions';
import {
ONBOARDING_METAMETRICS,
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
@ -33,6 +39,7 @@ export default function OnboardingWelcome() {
const [eventEmitter] = useState(new EventEmitter());
const currentKeyring = useSelector(getCurrentKeyring);
const firstTimeFlowType = useSelector(getFirstTimeFlowType);
const [termsChecked, setTermsChecked] = useState(false);
// Don't allow users to come back to this screen after they
// have already imported or created a wallet
@ -56,8 +63,23 @@ export default function OnboardingWelcome() {
account_type: 'metamask',
},
});
dispatch(setTermsOfUseLastAgreed(new Date().getTime()));
history.push(ONBOARDING_METAMETRICS);
};
const toggleTermsCheck = () => {
setTermsChecked((currentTermsChecked) => !currentTermsChecked);
};
const termsOfUse = t('agreeTermsOfUse', [
<a
className="create-new-vault__terms-link"
key="create-new-vault__link-text"
href="https://metamask.io/terms.html"
target="_blank"
rel="noopener noreferrer"
>
{t('terms')}
</a>,
]);
const onImportClick = () => {
dispatch(setFirstTimeFlowType('import'));
@ -68,6 +90,7 @@ export default function OnboardingWelcome() {
account_type: 'imported',
},
});
dispatch(setTermsOfUseLastAgreed(new Date().getTime()));
history.push(ONBOARDING_METAMETRICS);
};
@ -147,11 +170,35 @@ export default function OnboardingWelcome() {
</div>
</Carousel>
<ul className="onboarding-welcome__buttons">
<li>
<Box
alignItems={AlignItems.center}
className="onboarding__terms-of-use"
>
<CheckBox
id="onboarding__terms-checkbox"
className="onboarding__terms-checkbox"
dataTestId="onboarding-terms-checkbox"
checked={termsChecked}
onClick={toggleTermsCheck}
/>
<label
className="onboarding__terms-label"
htmlFor="onboarding__terms-checkbox"
>
<Text variant={TextVariant.bodyMd} marginLeft={2} as="span">
{termsOfUse}
</Text>
</label>
</Box>
</li>
<li>
<Button
data-testid="onboarding-create-wallet"
type="primary"
onClick={onCreateClick}
disabled={!termsChecked}
>
{t('onboardingCreateWallet')}
</Button>
@ -161,6 +208,7 @@ export default function OnboardingWelcome() {
data-testid="onboarding-import-wallet"
type="secondary"
onClick={onImportClick}
disabled={!termsChecked}
>
{t('onboardingImportWallet')}
</Button>

View File

@ -4,7 +4,10 @@ import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import initializedMockState from '../../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import { setFirstTimeFlowType } from '../../../store/actions';
import {
setFirstTimeFlowType,
setTermsOfUseLastAgreed,
} from '../../../store/actions';
import {
ONBOARDING_METAMETRICS,
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
@ -21,6 +24,11 @@ jest.mock('../../../store/actions.ts', () => ({
return type;
}),
),
setTermsOfUseLastAgreed: jest.fn().mockReturnValue(
jest.fn((type) => {
return type;
}),
),
}));
jest.mock('react-router-dom', () => ({
@ -81,19 +89,24 @@ describe('Onboarding Welcome Component', () => {
it('should set first time flow to create and route to metametrics', () => {
renderWithProvider(<OnboardingWelcome />, mockStore);
const termsCheckbox = screen.getByTestId('onboarding-terms-checkbox');
fireEvent.click(termsCheckbox);
const createWallet = screen.getByTestId('onboarding-create-wallet');
fireEvent.click(createWallet);
expect(setTermsOfUseLastAgreed).toHaveBeenCalled();
expect(setFirstTimeFlowType).toHaveBeenCalledWith('create');
});
it('should set first time flow to import and route to metametrics', () => {
renderWithProvider(<OnboardingWelcome />, mockStore);
const termsCheckbox = screen.getByTestId('onboarding-terms-checkbox');
fireEvent.click(termsCheckbox);
const createWallet = screen.getByTestId('onboarding-import-wallet');
fireEvent.click(createWallet);
expect(setTermsOfUseLastAgreed).toHaveBeenCalled();
expect(setFirstTimeFlowType).toHaveBeenCalledWith('import');
expect(mockHistoryPush).toHaveBeenCalledWith(ONBOARDING_METAMETRICS);
});

View File

@ -57,6 +57,7 @@ import {
import { TEMPLATED_CONFIRMATION_MESSAGE_TYPES } from '../pages/confirmation/templates';
import { STATIC_MAINNET_TOKEN_LIST } from '../../shared/constants/tokens';
import { DAY } from '../../shared/constants/time';
import { TERMS_OF_USE_LAST_UPDATED } from '../../shared/constants/terms';
import {
getNativeCurrency,
getConversionRate,
@ -995,6 +996,18 @@ export function getShowRecoveryPhraseReminder(state) {
return currentTime - recoveryPhraseReminderLastShown >= frequency;
}
export function getShowTermsOfUse(state) {
const { termsOfUseLastAgreed } = state.metamask;
if (!termsOfUseLastAgreed) {
return true;
}
return (
new Date(termsOfUseLastAgreed).getTime() <
new Date(TERMS_OF_USE_LAST_UPDATED).getTime()
);
}
export function getShowOutdatedBrowserWarning(state) {
const { outdatedBrowserWarningLastShown } = state.metamask;
if (!outdatedBrowserWarningLastShown) {

View File

@ -3980,6 +3980,12 @@ export function setRecoveryPhraseReminderLastShown(
};
}
export function setTermsOfUseLastAgreed(lastAgreed: number) {
return async () => {
await submitRequestToBackground('setTermsOfUseLastAgreed', [lastAgreed]);
};
}
export function setOutdatedBrowserWarningLastShown(lastShown: number) {
return async () => {
await submitRequestToBackground('setOutdatedBrowserWarningLastShown', [