From 59a3a808701682260d4ced31574dd85d65137945 Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 2 Mar 2022 17:59:52 +0100 Subject: [PATCH 01/11] feat: intial page modifications --- .../src/components/accounts/CreateAccount.js | 66 ++++++------------- .../recovery_setup/SetupRecoveryMethod.js | 2 +- .../frontend/src/translations/en.global.json | 10 +-- 3 files changed, 25 insertions(+), 53 deletions(-) diff --git a/packages/frontend/src/components/accounts/CreateAccount.js b/packages/frontend/src/components/accounts/CreateAccount.js index 3bc3625d8b..5809323129 100644 --- a/packages/frontend/src/components/accounts/CreateAccount.js +++ b/packages/frontend/src/components/accounts/CreateAccount.js @@ -2,7 +2,6 @@ import { getSearch } from 'connected-react-router'; import React, { Component } from 'react'; import { Translate } from 'react-localize-redux'; import { connect } from 'react-redux'; -import { Link } from 'react-router-dom'; import styled from 'styled-components'; import { ACCOUNT_ID_SUFFIX, IS_MAINNET, MIN_BALANCE_TO_CREATE } from '../../config'; @@ -17,19 +16,17 @@ import { clearLocalAlert } from '../../redux/actions/status'; import { selectAccountSlice, selectActiveAccountIdIsImplicitAccount } from '../../redux/slices/account'; import { selectStatusLocalAlert, selectStatusMainLoader } from '../../redux/slices/status'; import { selectNearTokenFiatValueUSD } from '../../redux/slices/tokenFiatValues'; -import isMobile from '../../utils/isMobile'; import { ENABLE_IDENTITY_VERIFIED_ACCOUNT } from '../../utils/wallet'; -import AccountNote from '../common/AccountNote'; import { getNearAndFiatValue } from '../common/balance/helpers'; +import Button from '../common/Button'; import FormButton from '../common/FormButton'; import Container from '../common/styled/Container.css'; import WhereToBuyNearModal from '../common/WhereToBuyNearModal'; import SafeTranslate from '../SafeTranslate'; import BrokenLinkIcon from '../svg/BrokenLinkIcon'; import FundNearIcon from '../svg/FundNearIcon'; -import AccountFormAccountId from './AccountFormAccountId'; const StyledContainer = styled(Container)` .input { @@ -147,47 +144,38 @@ class CreateAccount extends Component { } handleCreateAccount = async () => { - const { accountId, fundingAmount } = this.state; - const { - fundingContract, fundingKey, - fundingAccountId, - } = this.props; + // const { accountId, fundingAmount } = this.state; + // const { + // fundingContract, fundingKey, + // fundingAccountId, + // } = this.props; - this.setState({ loader: true }); + // this.setState({ loader: true }); - let queryString = ''; - if (fundingAccountId || fundingContract) { - const fundingOptions = fundingAccountId ? { fundingAccountId } : { fundingContract, fundingKey, fundingAmount }; - queryString = `?fundingOptions=${encodeURIComponent(JSON.stringify(fundingOptions))}`; - } + // let queryString = ''; + // if (fundingAccountId || fundingContract) { + // const fundingOptions = fundingAccountId ? { fundingAccountId } : { fundingContract, fundingKey, fundingAmount }; + // queryString = `?fundingOptions=${encodeURIComponent(JSON.stringify(fundingOptions))}`; + // } Mixpanel.track('CA Click create account button'); - this.props.history.push(`/set-recovery/${accountId}${queryString}`); + this.props.history.push(`/set-recovery/${'accountId'}${'queryString'}`); } render() { const { - loader, - accountId, invalidNearDrop, termsAccepted, whereToBuy } = this.state; const { - localAlert, - mainLoader, - checkNewAccount, - resetAccount, - clearLocalAlert, fundingContract, fundingKey, nearTokenFiatValueUSD, - locationSearch, activeAccountIdIsImplicit } = this.props; const isLinkDrop = fundingContract && fundingKey; - const useLocalAlert = accountId.length > 0 ? localAlert : undefined; const showTermsPage = IS_MAINNET && !isLinkDrop && !termsAccepted && !ENABLE_IDENTITY_VERIFIED_ACCOUNT; if (showTermsPage) { @@ -253,37 +241,21 @@ class CreateAccount extends Component { />

-

- - - - - + + {!termsAccepted &&
} -
+ {/*
{ Mixpanel.track('IE Click import existing account button'); }}> -
+ */} diff --git a/packages/frontend/src/components/accounts/recovery_setup/SetupRecoveryMethod.js b/packages/frontend/src/components/accounts/recovery_setup/SetupRecoveryMethod.js index 0f077e6d30..bc258d9e2a 100644 --- a/packages/frontend/src/components/accounts/recovery_setup/SetupRecoveryMethod.js +++ b/packages/frontend/src/components/accounts/recovery_setup/SetupRecoveryMethod.js @@ -528,7 +528,7 @@ class SetupRecoveryMethod extends Component { trackingId='SR Click submit button' data-test-id="submitSelectedRecoveryOption" > - + {isNewAccount && diff --git a/packages/frontend/src/translations/en.global.json b/packages/frontend/src/translations/en.global.json index eabaa525cc..6111801f89 100644 --- a/packages/frontend/src/translations/en.global.json +++ b/packages/frontend/src/translations/en.global.json @@ -330,8 +330,8 @@ "minCharacters": "Fewer than 2 characters", "separators": "Characters (_-) can be used as separators" }, - "pageText": "Enter an Account ID to use with your NEAR account. Your Account ID will be used for all NEAR operations, including sending and receiving assets.", - "pageTitle": "Reserve Account ID", + "pageText": "NEAR Wallet is a secure wallet and account manager for your accounts on the NEAR blockchain. Once you create an account, you’ll need it to interact with applications on NEAR, and to securely store your various tokens and collectibles (NFTs).", + "pageTitle": "Create Your Account", "recoverItHere": "Import Existing Account", "setupPassphrase": { "generatePassphrase": { @@ -1117,7 +1117,7 @@ "emailTitle": "Email", "existingPhraseDesc": "Protect your new address by sharing an existing passphrase.", "existingPhraseTitle": "Use an Existing Passphrase", - "header": "Choose a Security Method", + "header": "Choose a Recovery Method", "ledgerDesc": "Secure your account with a Ledger hardware device.", "ledgerTitle": "Ledger Hardware Wallet", "newPhraseDesc": "Protect your new address with a new and unique passphrase.", @@ -1128,7 +1128,7 @@ "phoneTitle": "Phone", "phraseDesc": "Generate and safely store a unique passphrase.", "phraseTitle": "Secure Passphrase", - "subHeader": "Select a method to secure and recover your account. This will be used to verify important activity, recover your account and access your account from other devices." + "subHeader": "Select a method to secure and recover your account, and to access it on other devices." }, "setupSeedPhrase": { "pageText": "Write down the following words in order and keep them somewhere safe. Anyone with access to it will also have access to your account! You’ll be asked to verify your passphrase next.", @@ -1415,9 +1415,9 @@ "desc": "Protect your account by requiring confirmation via SMS or email when authorizing transactions.", "disable": { "desc": "Keep in mind that transactions won't have to be confirmed with 2FA once it's disabled.", - "phoneDesc": "The SMS option for two-factor authentication is being deprecated, and cannot be re-enbaled.", "disable": "Disable 2FA", "keep": "No, keep 2FA", + "phoneDesc": "The SMS option for two-factor authentication is being deprecated, and cannot be re-enbaled.", "title": "Are you sure you want to disable 2FA?" }, "email": "Email", From 97ace6cff2de9ca01e76922b53b236e011bd6767 Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 16 Mar 2022 14:43:12 +0200 Subject: [PATCH 02/11] feat: account creation flow updates --- packages/frontend/package.json | 1 + packages/frontend/src/components/Routing.js | 28 ++++- .../components/accounts/SetupSeedPhrase.js | 1 + .../accounts/SetupSeedPhraseForm.js | 2 +- .../accounts/SetupSeedPhraseVerify.js | 97 +++++++++++--- .../new_account/ConfirmPassphrase.js | 8 +- .../new_account/SetupPassphraseNewAccount.js | 1 + .../src/components/common/modal/Modal.js | 1 + .../security/InactivityLockModal.js | 60 +++++++++ packages/frontend/src/routes/UnlockWallet.js | 42 +++++++ .../frontend/src/translations/en.global.json | 14 ++- packages/frontend/src/utils/arrayUtils.js | 3 + yarn.lock | 118 ++---------------- 13 files changed, 246 insertions(+), 130 deletions(-) create mode 100644 packages/frontend/src/components/security/InactivityLockModal.js create mode 100644 packages/frontend/src/routes/UnlockWallet.js create mode 100644 packages/frontend/src/utils/arrayUtils.js diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 78443675e1..3f69d9a90d 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -39,6 +39,7 @@ "react-google-recaptcha": "^2.1.0", "react-google-recaptcha-v3-near": "^2.0.0", "react-helmet": "^6.1.0", + "react-idle-timer": "^4.6.4", "react-localize-redux": "^3.5.3", "react-phone-number-input": "2.3.11", "react-redux": "^7.2.4", diff --git a/packages/frontend/src/components/Routing.js b/packages/frontend/src/components/Routing.js index cd406117e4..a3ec5d1abb 100644 --- a/packages/frontend/src/components/Routing.js +++ b/packages/frontend/src/components/Routing.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import { stringify } from 'query-string'; import React, { Component } from 'react'; import ReactDOMServer from 'react-dom/server'; +import IdleTimer from 'react-idle-timer'; import { withLocalize } from 'react-localize-redux'; import { connect } from 'react-redux'; import { Redirect, Switch } from 'react-router-dom'; @@ -25,6 +26,7 @@ import { SetupLedgerNewAccountWrapper } from '../routes/SetupLedgerNewAccountWra import { SetupPassphraseNewAccountWrapper } from '../routes/SetupPassphraseNewAccountWrapper'; import { SetupRecoveryImplicitAccountWrapper } from '../routes/SetupRecoveryImplicitAccountWrapper'; import { SignWrapper } from '../routes/SignWrapper'; +import UnlockWallet from '../routes/UnlockWallet'; import translations_en from '../translations/en.global.json'; import translations_pt from '../translations/pt.global.json'; import translations_ru from '../translations/ru.global.json'; @@ -77,6 +79,7 @@ import Navigation from './navigation/Navigation'; import { PageNotFound } from './page-not-found/PageNotFound'; import { Profile } from './profile/Profile'; import { ReceiveContainerWrapper } from './receive-money/ReceiveContainerWrapper'; +import InactivityLockModal from './security/InactivityLockModal'; import { SendContainerWrapper } from './send/SendContainerWrapper'; import { StakingContainer } from './staking/StakingContainer'; import Terms from './terms/Terms'; @@ -134,7 +137,8 @@ class Routing extends Component { super(props); this.state = { - isInactiveAccount: null + isInactiveAccount: null, + isUserActive: true }; this.pollTokenFiatValue = null; @@ -249,6 +253,14 @@ class Routing extends Component { this.stopPollingTokenFiatValue(); } + handleSetUserActive = () => { + return this.setState({...this.state,isUserActive: true }); + } + + handleSetUserIdle = () => { + return this.setState({...this.state, isUserActive: false }); + } + startPollingTokenFiatValue = () => { const { fetchTokenFiatValues } = this.props; @@ -313,6 +325,15 @@ class Routing extends Component { + + {!this.state.isUserActive && + + } { account.requestPending !== null && + {!isInactiveAccount && diff --git a/packages/frontend/src/components/accounts/SetupSeedPhraseForm.js b/packages/frontend/src/components/accounts/SetupSeedPhraseForm.js index e84323747d..6ff2693a06 100644 --- a/packages/frontend/src/components/accounts/SetupSeedPhraseForm.js +++ b/packages/frontend/src/components/accounts/SetupSeedPhraseForm.js @@ -124,7 +124,7 @@ const SetupSeedPhraseForm = ({ color='blue' data-test-id="continueToSeedPhraseVerificationButton" > - + ); diff --git a/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js b/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js index 7876641136..2958cebe20 100644 --- a/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js +++ b/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js @@ -3,17 +3,70 @@ import { Translate } from 'react-localize-redux'; import styled from 'styled-components'; import { RECAPTCHA_CHALLENGE_API_KEY } from '../../config'; +import { shuffleArray } from '../../utils/arrayUtils'; import { ENABLE_IDENTITY_VERIFIED_ACCOUNT } from '../../utils/wallet'; import FormButton from '../common/FormButton'; import LocalAlertBox from '../common/LocalAlertBox'; import { Recaptcha } from '../Recaptcha'; -import SafeTranslate from '../SafeTranslate'; // FIXME: Use `debug` npm package so we can keep some debug logging around but not spam the console everywhere const ENABLE_DEBUG_LOGGING = false; const debugLog = (...args) => ENABLE_DEBUG_LOGGING && console.log('SetupSeedPhraseVerify:', ...args); const CustomDiv = styled.div` + .seedphraseInputGrid{ + display:grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 8px; + counter-reset: input; + background: #FFFFFF; + box-shadow: 0px 45px 56px rgba(0, 0, 0, 0.07), 0px 10.0513px 12.5083px rgba(0, 0, 0, 0.0417275), 0px 2.99255px 3.72406px rgba(0, 0, 0, 0.0282725); + border-radius: 8px; + padding:16px; + + + .item{ + position:relative; + padding: 8px 16px 8px 32px; + background: #F0F0F1; + cursor:pointer; + margin-bottom: 0 !important; + min-width: 100%; + border-radius:0; + height: 37px; + display:block; + display:flex; + align-items:center; + + &:before { + position:absolute; + top:calc((100% - 15px) / 2); + left:12px; + counter-increment: input; + content: ""counter(input)""; + } + + &[data-active="true"] { + border: 2px solid #0072CE; + color: #2B9AF4; + } + } + } + + .seedphraseSelectionGrid{ + display:grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 8px; + margin-top: 32px; + + .item{ + padding: 8px 16px 8px 12px; + background: #D6EDFF; + color: #005497; + cursor:pointer; + height: 37px; + } + } input { margin-bottom: 30px !important; @@ -48,10 +101,9 @@ const CustomDiv = styled.div` `; -const SetupSeedPhraseVerify = ( - { +const SetupSeedPhraseVerify = (props,ref) => { + const { enterWord, - wordId, handleChangeWord, mainLoader, localAlert, @@ -60,13 +112,21 @@ const SetupSeedPhraseVerify = ( onSubmit, isLinkDrop, hasSeedPhraseRecovery, - handleStartOver - }, - ref -) => { + handleStartOver, + seedPhrase + }= props; debugLog('Re-rendering', { isNewAccount: isNewAccount }); const recaptchaRef = useRef(null); const [recaptchaToken, setRecaptchaToken] = useState(); + const [seedPhaseEntry, setSeedPhraseEntry] = useState(Array(12).fill('')); + const activeIndex = seedPhaseEntry.filter(Boolean).length; + const shuffledSeedPhrase= shuffleArray(seedPhrase.split(' ')); + + const handlePushWordIntoSeedhrase =(word)=>{ + const tempArray = [...seedPhaseEntry]; + tempArray[activeIndex]=word; + setSeedPhraseEntry([...tempArray]); + }; useImperativeHandle(ref, () => ({ reset() { @@ -79,12 +139,19 @@ const SetupSeedPhraseVerify = ( return ( -

- -

+
+ {seedPhaseEntry.map((word, i)=>{ + return
{word}
; + })} +
+
+ {shuffledSeedPhrase.filter((word)=>!seedPhaseEntry.includes(word)).map((word)=>{ + return
{ + handlePushWordIntoSeedhrase(word); + }}>{word}
; + })} +
+ {({ translate }) => ( { + console.log(passPhrase); return (
- {userInputValueWrongWord && -
- } + { userInputValueWrongWord &&
} { handleConfirmPassphrase({ implicitAccountId, recoveryKeyPair }); Mixpanel.track('SR-SP Verify finish'); }} + passPhrase={passPhrase} /> ); } diff --git a/packages/frontend/src/components/common/modal/Modal.js b/packages/frontend/src/components/common/modal/Modal.js index 62ef288607..006d6cfb6e 100644 --- a/packages/frontend/src/components/common/modal/Modal.js +++ b/packages/frontend/src/components/common/modal/Modal.js @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import ReactDom from 'react-dom'; + import classNames from '../../../utils/classNames'; import isMobile from '../../../utils/isMobile'; import CloseButton from './CloseButton'; diff --git a/packages/frontend/src/components/security/InactivityLockModal.js b/packages/frontend/src/components/security/InactivityLockModal.js new file mode 100644 index 0000000000..10a256312c --- /dev/null +++ b/packages/frontend/src/components/security/InactivityLockModal.js @@ -0,0 +1,60 @@ +import React from 'react'; +import { Translate } from 'react-localize-redux'; +import styled from 'styled-components'; + +import Button from '../common/Button'; +import Modal from '../common/modal/Modal'; + +const Container = styled.section` + width: 100%; + text-align:center; + + .header { + padding: 24px 16px; + border-bottom: 1px solid #F0F0F1; + + .ttl { + color: #24272A; + } + + .desc { + margin-top:16px; + font-size: 16px; + line-height: 150%; + text-align: center; + color: #72727A; + } + } + + .ctaBtn{ + margin-top: 16px; + } + + + +`; + +const InactivityLockModal = ({ isOpen, onClose }) => { + + return ( + + +
+

+

+
+ +
+
+ ); +}; + +export default InactivityLockModal; diff --git a/packages/frontend/src/routes/UnlockWallet.js b/packages/frontend/src/routes/UnlockWallet.js new file mode 100644 index 0000000000..a10547d167 --- /dev/null +++ b/packages/frontend/src/routes/UnlockWallet.js @@ -0,0 +1,42 @@ +import React from 'react'; +import styled from 'styled-components'; + +import Container from '../components/common/styled/Container.css'; + +const StyledContainer = styled(Container)` + h4 { + margin-top: 20px; + } + + input { + margin-bottom: 30px; + } + + .color-red { + margin-top: -20px; + } + + &&& { + button { + width: 100%; + margin-top: 20px; + &.link { + &.start-over { + margin: 30px auto 0 auto; + display: inherit; + } + } + } + } +`; + +const UnlockWallet = () => { + return ( + + + + + ); +}; + +export default UnlockWallet; diff --git a/packages/frontend/src/translations/en.global.json b/packages/frontend/src/translations/en.global.json index 6111801f89..6e876f0025 100644 --- a/packages/frontend/src/translations/en.global.json +++ b/packages/frontend/src/translations/en.global.json @@ -240,6 +240,7 @@ "moreInformation": "More information", "needToEditGoBack": "Need to edit? Go Back", "next": "Next", + "okIveSavedItSomewhere": "OK, I saved it somewhere", "protectAccount": "Protect Account", "receive": "Receive", "recoverAccount": "Recover Account", @@ -495,6 +496,11 @@ "withId": "Importing account: ${accountId}", "withIdFailed": "Failed to import account: ${accountId}" }, + "inactivityLockModal": { + "buttonCta": "I’m still here", + "desc": "Your wallet will soon be locked due to inactivity. Would you like to continue your session?", + "ttl": "Are you still there?" + }, "initialDeposit": { "claimAccount": { "desc": "Your deposit was received! Once claimed, your deposit will be transferred to your new account.", @@ -1131,8 +1137,8 @@ "subHeader": "Select a method to secure and recover your account, and to access it on other devices." }, "setupSeedPhrase": { - "pageText": "Write down the following words in order and keep them somewhere safe. Anyone with access to it will also have access to your account! You’ll be asked to verify your passphrase next.", - "pageTitle": "Setup Your Secure Passphrase", + "pageText": "This passphrase is the master-key for your account. Store it somewhere safe and do not share it. Anyone with these words will have full access to your account.", + "pageTitle": "Safely Store Your Secure Passphrase", "snackbarCopyImplicitAddress": "Funding Address Copied!", "snackbarCopySuccess": "Passphrase copied!" }, @@ -1143,8 +1149,8 @@ }, "setupSeedPhraseVerify": { "inputError": "Please check your passphrase and try again.", - "pageText": "Enter the following word from your recovery phrase to complete the setup process.", - "pageTitle": "Verify Phrase", + "pageText": "Click or tap each word in the correct order to complete your passphrase.", + "pageTitle": "Verify Passphrase", "startOverText": "Didn't write it down?" }, "sign": { diff --git a/packages/frontend/src/utils/arrayUtils.js b/packages/frontend/src/utils/arrayUtils.js new file mode 100644 index 0000000000..dca48442e8 --- /dev/null +++ b/packages/frontend/src/utils/arrayUtils.js @@ -0,0 +1,3 @@ +export const shuffleArray=(array) =>{ + return [...array].sort(() => Math.random() - 0.5); +}; diff --git a/yarn.lock b/yarn.lock index 950d936c89..8cf3b24a3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1119,14 +1119,6 @@ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== -"@hypnosphi/create-react-context@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz#f8bfebdc7665f5d426cba3753e0e9c7d3154d7c6" - integrity sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - "@iarna/toml@^2.2.0": version "2.2.5" resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" @@ -2035,15 +2027,6 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@near-wallet/feature-flags@^0.0.4": - version "0.0.4" - resolved "https://registry.yarnpkg.com/@near-wallet/feature-flags/-/feature-flags-0.0.4.tgz#281a15ad66f9ba0c66bb63f81ea0b21a228071a9" - integrity sha512-TUu1io4U1CzvV5gGzLMGwQLFuA7Hj/RmRD1y0Ys1MdCcyErBced/cLIymQJtC5zZTYW6JlbJTQ3EmZb+HUaG4g== - dependencies: - fs-extra "^10.0.0" - ini "^1.3.4" - inquirer "^8.2.0" - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2356,7 +2339,6 @@ estree-walker "^1.0.1" picomatch "^2.2.2" - "@sentry/browser@^6.4.1": version "6.16.1" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.16.1.tgz#4270ab0fbd1de425e339b3e7a364feb09f470a87" @@ -2435,23 +2417,6 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@stardust-ui/react-component-event-listener@~0.38.0": - version "0.38.0" - resolved "https://registry.yarnpkg.com/@stardust-ui/react-component-event-listener/-/react-component-event-listener-0.38.0.tgz#1787faded94b40ad41226e6289baf13e701c6e7f" - integrity sha512-sIP/e0dyOrrlb8K7KWumfMxj/gAifswTBC4o68Aa+C/GA73ccRp/6W1VlHvF/dlOR4KLsA+5SKnhjH36xzPsWg== - dependencies: - "@babel/runtime" "^7.1.2" - prop-types "^15.7.2" - -"@stardust-ui/react-component-ref@~0.38.0": - version "0.38.0" - resolved "https://registry.yarnpkg.com/@stardust-ui/react-component-ref/-/react-component-ref-0.38.0.tgz#52d555f2d5edd213c923c93a106f7de940e427ef" - integrity sha512-xjs6WnvJVueSIXMWw0C3oWIgAPpcD03qw43oGOjUXqFktvpNkB73JoKIhS4sCrtQxBdct75qqr4ZL6JiyPcESw== - dependencies: - "@babel/runtime" "^7.1.2" - prop-types "^15.7.2" - react-is "^16.6.3" - "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -3873,7 +3838,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.2.5, classnames@^2.2.6: +classnames@^2.2.5: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== @@ -4836,18 +4801,6 @@ dedent@0.7.0, dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-equal@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -5722,7 +5675,7 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -exenv@^1.2.0, exenv@^1.2.2: +exenv@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= @@ -7002,11 +6955,6 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ini@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" - integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== - init-package-json@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.3.tgz#c8ae4f2a4ad353bcbc089e5ffe98a8f1a314e8fd" @@ -7149,14 +7097,6 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -7421,7 +7361,7 @@ is-reference@^1.2.1: dependencies: "@types/estree" "*" -is-regex@^1.0.4, is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.3, is-regex@^1.1.4: +is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.3, is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -8049,11 +7989,6 @@ jpeg-js@^0.4.2: resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== -jquery@x.*: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" - integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== - js-sha256@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" @@ -8240,11 +8175,6 @@ just-curry-it@^3.1.0: resolved "https://registry.yarnpkg.com/just-curry-it/-/just-curry-it-3.2.1.tgz#7bb18284c8678ed816bfc5c19e44400605fbe461" integrity sha512-Q8206k8pTY7krW32cdmPsP+DqqLgWx/hYPSj9/+7SYqSqz7UuwPbfSe07lQtvuuaVyiSJveXk0E5RydOuWwsEg== -keyboard-key@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/keyboard-key/-/keyboard-key-1.1.0.tgz#6f2e8e37fa11475bb1f1d65d5174f1b35653f5b7" - integrity sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ== - keypress@0.1.x: version "0.1.0" resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.1.0.tgz#4a3188d4291b66b4f65edb99f806aa9ae293592a" @@ -9552,7 +9482,7 @@ object-inspect@~1.4.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.4.1.tgz#37ffb10e71adaf3748d05f713b4c9452f402cbc4" integrity sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw== -object-is@^1.0.1, object-is@^1.0.2, object-is@^1.1.2: +object-is@^1.0.2, object-is@^1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== @@ -10291,11 +10221,6 @@ pngjs@^5.0.0: resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== -popper.js@^1.14.4: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -11073,7 +10998,12 @@ react-helmet@^6.1.0: react-fast-compare "^3.1.1" react-side-effect "^2.1.0" -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: +react-idle-timer@^4.6.4: + version "4.6.4" + resolved "https://registry.yarnpkg.com/react-idle-timer/-/react-idle-timer-4.6.4.tgz#71ba954ba6f464df24d46a94e63c5ef19f7319dc" + integrity sha512-iq61dPud8fgj7l1KOJEY5pyiD532fW0KcIe/5XUe/0lB/4Vytoy4tZBlLGSiYodPzKxTL6HyKoOmG6tyzjD7OQ== + +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -11121,19 +11051,6 @@ react-phone-number-input@2.3.11: react-lifecycles-compat "^3.0.4" react-responsive-ui "^0.14.123" -react-popper@^1.3.4: - version "1.3.11" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.11.tgz#a2cc3f0a67b75b66cfa62d2c409f9dd1fcc71ffd" - integrity sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg== - dependencies: - "@babel/runtime" "^7.1.2" - "@hypnosphi/create-react-context" "^0.3.1" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" - warning "^4.0.2" - react-redux@^7.2.4: version "7.2.6" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa" @@ -11270,9 +11187,6 @@ read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" read-pkg-up@^7.0.1: version "7.0.1" @@ -11433,7 +11347,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: +regexp.prototype.flags@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== @@ -11820,7 +11734,6 @@ seamless-immutable@^7.1.3: resolved "https://registry.yarnpkg.com/seamless-immutable/-/seamless-immutable-7.1.4.tgz#6e9536def083ddc4dea0207d722e0e80d0f372f8" integrity sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A== - "semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -13014,11 +12927,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -13368,7 +13276,7 @@ walker@^1.0.7: dependencies: makeerror "1.0.12" -warning@^4.0.2, warning@^4.0.3: +warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== @@ -13706,4 +13614,4 @@ yazl@^2.5.1: yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== \ No newline at end of file + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== From 9f10bb4165bc7a3372aca3dd011bd335dbb1c6a4 Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 16 Mar 2022 18:42:29 +0200 Subject: [PATCH 03/11] feat: password modals, set password and unlock --- packages/frontend/src/components/Routing.js | 13 +- .../frontend/src/components/common/Button.js | 30 ++++- .../security/IntroducingPasswordsModal.js | 59 +++++++++ .../security/KeepPasswordsSafeModal.js | 59 +++++++++ .../security/ResetWalletPasswordModal.js | 74 ++++++++++++ .../frontend/src/images/icon-lock-outline.svg | 4 + packages/frontend/src/routes/SetPassword.js | 94 +++++++++++++++ packages/frontend/src/routes/UnlockWallet.js | 113 ++++++++++++++---- .../frontend/src/translations/en.global.json | 22 ++++ yarn.lock | 16 ++- 10 files changed, 450 insertions(+), 34 deletions(-) create mode 100644 packages/frontend/src/components/security/IntroducingPasswordsModal.js create mode 100644 packages/frontend/src/components/security/KeepPasswordsSafeModal.js create mode 100644 packages/frontend/src/components/security/ResetWalletPasswordModal.js create mode 100644 packages/frontend/src/images/icon-lock-outline.svg create mode 100644 packages/frontend/src/routes/SetPassword.js diff --git a/packages/frontend/src/components/Routing.js b/packages/frontend/src/components/Routing.js index a3ec5d1abb..7d358b893c 100644 --- a/packages/frontend/src/components/Routing.js +++ b/packages/frontend/src/components/Routing.js @@ -22,6 +22,7 @@ import { selectAccountSlice } from '../redux/slices/account'; import { actions as tokenFiatValueActions } from '../redux/slices/tokenFiatValues'; import { CreateImplicitAccountWrapper } from '../routes/CreateImplicitAccountWrapper'; import { LoginWrapper } from '../routes/LoginWrapper'; +import SetPassword from '../routes/SetPassword'; import { SetupLedgerNewAccountWrapper } from '../routes/SetupLedgerNewAccountWrapper'; import { SetupPassphraseNewAccountWrapper } from '../routes/SetupPassphraseNewAccountWrapper'; import { SetupRecoveryImplicitAccountWrapper } from '../routes/SetupRecoveryImplicitAccountWrapper'; @@ -87,9 +88,7 @@ import { Wallet } from './wallet/Wallet'; import '../index.css'; -const { - fetchTokenFiatValues -} = tokenFiatValueActions; +const { fetchTokenFiatValues } = tokenFiatValueActions; const { getAccountHelperWalletState, @@ -327,7 +326,6 @@ class Routing extends Component { @@ -580,9 +578,14 @@ class Routing extends Component { /> + {!isInactiveAccount && props.theme === 'secondary' ? '#ffffff' : '#0072CE'}; - border: 2px solid ${(props) => props.theme === 'secondary' ? '#cccccc' : '#0072CE'}; - color: ${(props) => props.theme === 'secondary' ? '#888888' : 'white'}; + background-color: ${(props) => backgroundColorMap[props.theme]}; + border: 2px solid ${(props) => borderColorMap[props.theme]}; + color: ${(props) => colorMap[props.theme]}; @media (min-width: 768px) { &:enabled { &:hover { - background-color: ${(props) => props.theme === 'secondary' ? '#cccccc' : '#007fe6'}; + background-color: ${(props) => backgroundColorHoverMap[props.theme]}; color: white; } } @@ -50,7 +70,7 @@ const Button = (props) => ( Button.propTypes = { disabled: PropTypes.bool, - theme: PropTypes.oneOf(['primary', 'secondary']), + theme: PropTypes.oneOf(['primary', 'secondary', 'destructive']), fullWidth: PropTypes.bool, }; diff --git a/packages/frontend/src/components/security/IntroducingPasswordsModal.js b/packages/frontend/src/components/security/IntroducingPasswordsModal.js new file mode 100644 index 0000000000..0446b37df9 --- /dev/null +++ b/packages/frontend/src/components/security/IntroducingPasswordsModal.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { Translate } from 'react-localize-redux'; +import styled from 'styled-components'; + +import Button from '../common/Button'; +import Modal from '../common/modal/Modal'; + +const Container = styled.section` + width: 100%; + text-align:center; + + .header { + padding: 24px 16px; + border-bottom: 1px solid #F0F0F1; + + .ttl { + color: #24272A; + } + + .desc { + margin-top:16px; + font-size: 16px; + line-height: 150%; + text-align: center; + color: #72727A; + } + } + + .ctaBtn{ + margin-top: 16px; + } + + + +`; + +const IntroducingPasswordsModal = ({ isOpen, onClose }) => { + return ( + + +
+

+

+
+ +
+
+ ); +}; + +export default IntroducingPasswordsModal; diff --git a/packages/frontend/src/components/security/KeepPasswordsSafeModal.js b/packages/frontend/src/components/security/KeepPasswordsSafeModal.js new file mode 100644 index 0000000000..d14b327623 --- /dev/null +++ b/packages/frontend/src/components/security/KeepPasswordsSafeModal.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { Translate } from 'react-localize-redux'; +import styled from 'styled-components'; + +import Button from '../common/Button'; +import Modal from '../common/modal/Modal'; + +const Container = styled.section` + width: 100%; + text-align:center; + + .header { + padding: 24px 16px; + border-bottom: 1px solid #F0F0F1; + + .ttl { + color: #24272A; + } + + .desc { + margin-top:16px; + font-size: 16px; + line-height: 150%; + text-align: center; + color: #72727A; + } + } + + .ctaBtn{ + margin-top: 16px; + } + + + +`; + +const KeepPasswordsSafeModal = ({ isOpen, onClose }) => { + return ( + + +
+

+

+
+ +
+
+ ); +}; + +export default KeepPasswordsSafeModal; diff --git a/packages/frontend/src/components/security/ResetWalletPasswordModal.js b/packages/frontend/src/components/security/ResetWalletPasswordModal.js new file mode 100644 index 0000000000..50105d65ee --- /dev/null +++ b/packages/frontend/src/components/security/ResetWalletPasswordModal.js @@ -0,0 +1,74 @@ +import React, {useState} from 'react'; +import { Translate } from 'react-localize-redux'; +import styled from 'styled-components'; + +import Button from '../common/Button'; +import Checkbox from '../common/Checkbox'; +import Modal from '../common/modal/Modal'; + +const Container = styled.section` + width: 100%; + text-align:center; + + .header { + padding: 24px 16px; + + .ttl { + color: #24272A; + } + + .desc { + margin-top:16px; + font-size: 16px; + line-height: 150%; + text-align: center; + color: #72727A; + } + } + + .consentWrapper{ + background: #FFDEDF; + display: flex; + padding: 16px; + } + + .ctaBtn{ + margin-top: 16px; + } +`; + +const ResetWalletPasswordModal = ({ isOpen, onClose }) => { + const [ consentGranted, setConsentGranted ]=useState(true); + return ( + + +
+

+

+
+
+ +
+ + +
+
+ ); +}; + +export default ResetWalletPasswordModal; diff --git a/packages/frontend/src/images/icon-lock-outline.svg b/packages/frontend/src/images/icon-lock-outline.svg new file mode 100644 index 0000000000..8f4d7c77f2 --- /dev/null +++ b/packages/frontend/src/images/icon-lock-outline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/frontend/src/routes/SetPassword.js b/packages/frontend/src/routes/SetPassword.js new file mode 100644 index 0000000000..333b06c645 --- /dev/null +++ b/packages/frontend/src/routes/SetPassword.js @@ -0,0 +1,94 @@ +import React from 'react'; +import {Translate} from 'react-localize-redux'; +import styled from 'styled-components'; + +import Button from '../components/common/Button'; +import Container from '../components/common/styled/Container.css'; + + + +const StyledContainer = styled(Container)` + form{ + header{ + .ttl{ + + } + .desc{ + margin-top: 16px; + font-size: 16px; + color: #72727A; + } + } + + .inputWrapper{ + margin-top: 52px; + + input { + + } + } + + .btn{ + margin-top: 24px; + } + + .forgotPassword{ + text-align: center; + margin-top: 20px; + color: #0072CE; + cursor: pointer; + } + } +`; + + +const SetPassword = () => { + // const initialState ={ + // newPassword: "", + // confirmPassword: "", + // }; + // const [state,setState]=useState(initialState); + // const handleStateUpdate = (data)=>{ + // return setState({...state, ...data}); + // }; + return ( + + +
+

+ +

+

+
+
+ + +
+
+ + + {/*

Incorrect password. 2 attempts remaining.

*/} +
+ + +
+ ); +}; + +export default SetPassword; diff --git a/packages/frontend/src/routes/UnlockWallet.js b/packages/frontend/src/routes/UnlockWallet.js index a10547d167..91565fa0d7 100644 --- a/packages/frontend/src/routes/UnlockWallet.js +++ b/packages/frontend/src/routes/UnlockWallet.js @@ -1,40 +1,107 @@ -import React from 'react'; +import React, { useState } from 'react'; import styled from 'styled-components'; +import Button from '../components/common/Button'; import Container from '../components/common/styled/Container.css'; +import ResetWalletPasswordModal from '../components/security/ResetWalletPasswordModal'; +import EmailIcon from '../images/icon-lock-outline.svg'; -const StyledContainer = styled(Container)` - h4 { - margin-top: 20px; - } - input { - margin-bottom: 30px; - } - .color-red { - margin-top: -20px; - } - - &&& { - button { - width: 100%; - margin-top: 20px; - &.link { - &.start-over { - margin: 30px auto 0 auto; - display: inherit; +const StyledContainer = styled(Container)` + form{ + header{ + text-align: center; + .iconWrapper{ + background: #F0F0F1; + border-radius: 50px; + width: 56px; + height: 56px; + margin: auto; + display: flex; + align-items: center; + justify-content: center; + img{ + width: 24px; + height: 24px; } } + .ttl{ + + } + .desc{ + margin-top: 16px; + font-size: 16px; + color: #72727A; + } } + + .inputWrapper{ + margin-top: 52px; + + input { + + } + } + + .btn{ + margin-top: 24px; + } + + .forgotPassword{ + text-align: center; + margin-top: 20px; + color: #0072CE; + cursor: pointer; + } } `; + const UnlockWallet = () => { + const initialState ={ + showPasswordResetModal: false + }; + const [state,setState]=useState(initialState); + const handleStateUpdate = (data)=>{ + return setState({...state, ...data}); + }; return ( - - - + +
+
+
+ email icon +
+

Unlock wallet

+

Your wallet was locked due to inactivity. Enter your browser password to unlock it.

+
+
+ + +

Incorrect password. 2 attempts remaining.

+
+ + +
{handleStateUpdate({showPasswordResetModal:true});}} + > + I forgot my password +
+
+ { state.showPasswordResetModal && + {handleStateUpdate({showPasswordResetModal:false});}}/> + }
); }; diff --git a/packages/frontend/src/translations/en.global.json b/packages/frontend/src/translations/en.global.json index 6e876f0025..da7a5e8afb 100644 --- a/packages/frontend/src/translations/en.global.json +++ b/packages/frontend/src/translations/en.global.json @@ -531,6 +531,14 @@ "title": "Word #${wordId}" } }, + "introducingPasswordsModal": { + "desc": "NEAR Wallet now uses browser passwords to provide additional security to your accounts on the web.\n\nContinue to set up a browser password for your wallet.", + "ttl": "Introducing Browser Passwords!" + }, + "keepPasswordsSafeModal": { + "desc": "NEAR Wallet is not able to recover your password for you.\n\nIf you lose it, you’ll have to reset your wallet and recover any accounts you may have previously imported.", + "ttl": "Keep Your Password Safe!" + }, "landing": { "banner": "NEAR Wallet is in Private Beta", "desc": "Securely store and stake your NEAR tokens and compatible assets with NEAR Wallet.", @@ -957,6 +965,12 @@ "title": "Release Notes" }, "reservedForFeesInfo": "Up to ${data} NEAR is reserved to cover the cost of transactions.", + "resetWalletModal": { + "buttonCta": "Reset & Recover", + "consentText": "I’ve confirmed that I have access to the recovery information for my accounts.", + "desc": "NEAR Wallet is not able to recover your browser password for you.
If you’ve lost it, you’ll need to reset your wallet and manually recover any accounts you may have previously added. Make sure you have your recovery information for each account before resetting.", + "ttl": "Reset Your Wallet?" + }, "selectAccountDropdown": { "account": "Account", "createAccount": "Create New Account", @@ -1056,6 +1070,14 @@ } } }, + "setPassword": { + "buttonCta": "Set password", + "confirmPassword": "Confirm Password", + "consentText": "I understand that NEAR Wallet cannot recover this password for me. Learn more", + "desc": "Set a password to secure your wallet while using Brave Browser on this device.", + "newPassword": "New Password", + "ttl": "Set a Browser Password" + }, "setRecoveryConfirm": { "didNotReceive": "Didn't receive your code?", "email": "email address", diff --git a/yarn.lock b/yarn.lock index 8cf3b24a3c..b306ae68fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2027,6 +2027,15 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@near-wallet/feature-flags@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-wallet/feature-flags/-/feature-flags-0.0.4.tgz#281a15ad66f9ba0c66bb63f81ea0b21a228071a9" + integrity sha512-TUu1io4U1CzvV5gGzLMGwQLFuA7Hj/RmRD1y0Ys1MdCcyErBced/cLIymQJtC5zZTYW6JlbJTQ3EmZb+HUaG4g== + dependencies: + fs-extra "^10.0.0" + ini "^2.0.0" + inquirer "^8.2.0" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -6023,7 +6032,7 @@ find-root@1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@^2.0.0, find-up@^2.1.0: +find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= @@ -6955,6 +6964,11 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ini@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + init-package-json@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.3.tgz#c8ae4f2a4ad353bcbc089e5ffe98a8f1a314e8fd" From 3fa952c5a1a7fe1d42277b21889ce6b54a35fc0e Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 16 Mar 2022 18:49:35 +0200 Subject: [PATCH 04/11] feat: profile browser password widget(WIP) --- packages/frontend/src/components/profile/Profile.js | 5 +++++ packages/frontend/src/translations/en.global.json | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/packages/frontend/src/components/profile/Profile.js b/packages/frontend/src/components/profile/Profile.js index db5673416d..dbbf7fe38c 100644 --- a/packages/frontend/src/components/profile/Profile.js +++ b/packages/frontend/src/components/profile/Profile.js @@ -267,6 +267,11 @@ export function Profile({ match }) {

+
+
+

+
+
{!account.ledgerKey && <>
diff --git a/packages/frontend/src/translations/en.global.json b/packages/frontend/src/translations/en.global.json index da7a5e8afb..bd2e8fefea 100644 --- a/packages/frontend/src/translations/en.global.json +++ b/packages/frontend/src/translations/en.global.json @@ -742,6 +742,10 @@ "authorizedApps": { "title": "Authorized Apps" }, + "browserPassword": { + "desc": "Change the password used to secure your wallet while using Brave Browser on this device.", + "ttl": "Browser Password" + }, "details": { "availableBalance": "Available Balance", "locked": "Locked", From ae7b3be719ce5195deba4ed3c5c44d9b283f5175 Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 16 Mar 2022 20:36:36 +0200 Subject: [PATCH 05/11] feat: profile browser password complete --- .../src/components/profile/Profile.js | 2 + .../browser-password/BrowserPassword.js | 67 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 packages/frontend/src/components/profile/browser-password/BrowserPassword.js diff --git a/packages/frontend/src/components/profile/Profile.js b/packages/frontend/src/components/profile/Profile.js index dbbf7fe38c..abcd8a038e 100644 --- a/packages/frontend/src/components/profile/Profile.js +++ b/packages/frontend/src/components/profile/Profile.js @@ -38,6 +38,7 @@ import HardwareDevices from './hardware_devices/HardwareDevices'; import MobileSharingWrapper from './mobile_sharing/MobileSharingWrapper'; import RecoveryContainer from './Recovery/RecoveryContainer'; import TwoFactorAuth from './two_factor/TwoFactorAuth'; +import BrowserPassword from "./browser-password/BrowserPassword"; const { fetchRecoveryMethods } = recoveryMethodsActions; @@ -271,6 +272,7 @@ export function Profile({ match }) {

+
{!account.ledgerKey && <> diff --git a/packages/frontend/src/components/profile/browser-password/BrowserPassword.js b/packages/frontend/src/components/profile/browser-password/BrowserPassword.js new file mode 100644 index 0000000000..8f9e2c8aee --- /dev/null +++ b/packages/frontend/src/components/profile/browser-password/BrowserPassword.js @@ -0,0 +1,67 @@ +import React from 'react'; +import styled from 'styled-components'; + +import Button from '../../common/Button'; +import Card from '../../common/styled/Card.css'; + +const Container = styled(Card)` + margin-top: 30px; + padding: 16px; + + p{ + font-size: 14px; + line-height: 150%; + color: #A2A2A8; + } + .topSection { + display: flex; + align-items: center; + justify-content: space-between; + + div{ + .ttl{ + font-size: 14px; + line-height: 150%; + color: #3F4045; + } + .desc{ + margin-top: 4px; + } + } + + button { + height: 40px; + width: 100px; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + margin: 0; + color: #0072CE; + background: #F0F0F1; + font-size: 14px; + border: none; + } + } +`; + +const BrowserPassword = () => { + return ( + +
+
+

Brave Browser

+

Desktop • v23.13

+
+ + +
+

Enabled Jan 08, 2020

+
+ ); +}; + +export default BrowserPassword; + From ef0f3c8012a199063f935af96f7c740d9f8ba39c Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 16 Mar 2022 20:44:20 +0200 Subject: [PATCH 06/11] feat: profile browser password complete --- packages/frontend/src/components/profile/Profile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/profile/Profile.js b/packages/frontend/src/components/profile/Profile.js index abcd8a038e..af69d2e5bb 100644 --- a/packages/frontend/src/components/profile/Profile.js +++ b/packages/frontend/src/components/profile/Profile.js @@ -34,11 +34,11 @@ import UserIcon from '../svg/UserIcon'; import AuthorizedApp from './authorized_apps/AuthorizedApp'; import BalanceContainer from './balances/BalanceContainer'; import LockupAvailTransfer from './balances/LockupAvailTransfer'; +import BrowserPassword from './browser-password/BrowserPassword'; import HardwareDevices from './hardware_devices/HardwareDevices'; import MobileSharingWrapper from './mobile_sharing/MobileSharingWrapper'; import RecoveryContainer from './Recovery/RecoveryContainer'; import TwoFactorAuth from './two_factor/TwoFactorAuth'; -import BrowserPassword from "./browser-password/BrowserPassword"; const { fetchRecoveryMethods } = recoveryMethodsActions; From adeb28ff8aa0393b102648c4ad16862671a359f1 Mon Sep 17 00:00:00 2001 From: Philip Obosi Date: Wed, 16 Mar 2022 20:52:12 +0200 Subject: [PATCH 07/11] feat: separate route for change password --- packages/frontend/src/components/Routing.js | 7 ++ .../frontend/src/routes/ChangePassword.js | 80 +++++++++++++++++++ packages/frontend/src/routes/SetPassword.js | 18 +---- .../frontend/src/translations/en.global.json | 7 ++ 4 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 packages/frontend/src/routes/ChangePassword.js diff --git a/packages/frontend/src/components/Routing.js b/packages/frontend/src/components/Routing.js index 7d358b893c..3817cf6c21 100644 --- a/packages/frontend/src/components/Routing.js +++ b/packages/frontend/src/components/Routing.js @@ -20,6 +20,7 @@ import * as accountActions from '../redux/actions/account'; import { handleClearAlert } from '../redux/reducers/status'; import { selectAccountSlice } from '../redux/slices/account'; import { actions as tokenFiatValueActions } from '../redux/slices/tokenFiatValues'; +import ChangePassword from '../routes/ChangePassword'; import { CreateImplicitAccountWrapper } from '../routes/CreateImplicitAccountWrapper'; import { LoginWrapper } from '../routes/LoginWrapper'; import SetPassword from '../routes/SetPassword'; @@ -88,6 +89,7 @@ import { Wallet } from './wallet/Wallet'; import '../index.css'; + const { fetchTokenFiatValues } = tokenFiatValueActions; const { @@ -586,6 +588,11 @@ class Routing extends Component { path='/security/set-password' component={SetPassword} /> + {!isInactiveAccount && { + // const initialState ={ + // newPassword: "", + // confirmPassword: "", + // }; + // const [state,setState]=useState(initialState); + // const handleStateUpdate = (data)=>{ + // return setState({...state, ...data}); + // }; + return ( + +
+
+

+ +

+

+
+
+ + +
+
+ + + {/*

Incorrect password. 2 attempts remaining.

*/} +
+ +
+
+ ); +}; + +export default ChangePassword; diff --git a/packages/frontend/src/routes/SetPassword.js b/packages/frontend/src/routes/SetPassword.js index 333b06c645..cf35fa1fc4 100644 --- a/packages/frontend/src/routes/SetPassword.js +++ b/packages/frontend/src/routes/SetPassword.js @@ -62,25 +62,11 @@ const SetPassword = () => {
- +
- + {/*

Incorrect password. 2 attempts remaining.

*/}
+ + +

Enabled Jan 08, 2020

From a90cfaeb9d0ac963e11f4a227a88c82af08e166e Mon Sep 17 00:00:00 2001 From: gutsyphilip Date: Sun, 20 Mar 2022 23:16:22 +0200 Subject: [PATCH 10/11] fix: revert new verify seed phrase UI --- .../accounts/SetupSeedPhraseVerify.js | 97 +++---------------- 1 file changed, 15 insertions(+), 82 deletions(-) diff --git a/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js b/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js index 2958cebe20..7876641136 100644 --- a/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js +++ b/packages/frontend/src/components/accounts/SetupSeedPhraseVerify.js @@ -3,70 +3,17 @@ import { Translate } from 'react-localize-redux'; import styled from 'styled-components'; import { RECAPTCHA_CHALLENGE_API_KEY } from '../../config'; -import { shuffleArray } from '../../utils/arrayUtils'; import { ENABLE_IDENTITY_VERIFIED_ACCOUNT } from '../../utils/wallet'; import FormButton from '../common/FormButton'; import LocalAlertBox from '../common/LocalAlertBox'; import { Recaptcha } from '../Recaptcha'; +import SafeTranslate from '../SafeTranslate'; // FIXME: Use `debug` npm package so we can keep some debug logging around but not spam the console everywhere const ENABLE_DEBUG_LOGGING = false; const debugLog = (...args) => ENABLE_DEBUG_LOGGING && console.log('SetupSeedPhraseVerify:', ...args); const CustomDiv = styled.div` - .seedphraseInputGrid{ - display:grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 8px; - counter-reset: input; - background: #FFFFFF; - box-shadow: 0px 45px 56px rgba(0, 0, 0, 0.07), 0px 10.0513px 12.5083px rgba(0, 0, 0, 0.0417275), 0px 2.99255px 3.72406px rgba(0, 0, 0, 0.0282725); - border-radius: 8px; - padding:16px; - - - .item{ - position:relative; - padding: 8px 16px 8px 32px; - background: #F0F0F1; - cursor:pointer; - margin-bottom: 0 !important; - min-width: 100%; - border-radius:0; - height: 37px; - display:block; - display:flex; - align-items:center; - - &:before { - position:absolute; - top:calc((100% - 15px) / 2); - left:12px; - counter-increment: input; - content: ""counter(input)""; - } - - &[data-active="true"] { - border: 2px solid #0072CE; - color: #2B9AF4; - } - } - } - - .seedphraseSelectionGrid{ - display:grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 8px; - margin-top: 32px; - - .item{ - padding: 8px 16px 8px 12px; - background: #D6EDFF; - color: #005497; - cursor:pointer; - height: 37px; - } - } input { margin-bottom: 30px !important; @@ -101,9 +48,10 @@ const CustomDiv = styled.div` `; -const SetupSeedPhraseVerify = (props,ref) => { - const { +const SetupSeedPhraseVerify = ( + { enterWord, + wordId, handleChangeWord, mainLoader, localAlert, @@ -112,21 +60,13 @@ const SetupSeedPhraseVerify = (props,ref) => { onSubmit, isLinkDrop, hasSeedPhraseRecovery, - handleStartOver, - seedPhrase - }= props; + handleStartOver + }, + ref +) => { debugLog('Re-rendering', { isNewAccount: isNewAccount }); const recaptchaRef = useRef(null); const [recaptchaToken, setRecaptchaToken] = useState(); - const [seedPhaseEntry, setSeedPhraseEntry] = useState(Array(12).fill('')); - const activeIndex = seedPhaseEntry.filter(Boolean).length; - const shuffledSeedPhrase= shuffleArray(seedPhrase.split(' ')); - - const handlePushWordIntoSeedhrase =(word)=>{ - const tempArray = [...seedPhaseEntry]; - tempArray[activeIndex]=word; - setSeedPhraseEntry([...tempArray]); - }; useImperativeHandle(ref, () => ({ reset() { @@ -139,19 +79,12 @@ const SetupSeedPhraseVerify = (props,ref) => { return ( -
- {seedPhaseEntry.map((word, i)=>{ - return
{word}
; - })} -
-
- {shuffledSeedPhrase.filter((word)=>!seedPhaseEntry.includes(word)).map((word)=>{ - return
{ - handlePushWordIntoSeedhrase(word); - }}>{word}
; - })} -
- +

+ +

{({ translate }) => ( { Date: Mon, 21 Mar 2022 20:46:45 +0200 Subject: [PATCH 11/11] chore: cleanup seedphrase implementation --- packages/frontend/src/components/accounts/SetupSeedPhrase.js | 1 - packages/frontend/src/utils/arrayUtils.js | 3 --- 2 files changed, 4 deletions(-) delete mode 100644 packages/frontend/src/utils/arrayUtils.js diff --git a/packages/frontend/src/components/accounts/SetupSeedPhrase.js b/packages/frontend/src/components/accounts/SetupSeedPhrase.js index 7c9287d478..63a7e99293 100644 --- a/packages/frontend/src/components/accounts/SetupSeedPhrase.js +++ b/packages/frontend/src/components/accounts/SetupSeedPhrase.js @@ -265,7 +265,6 @@ class SetupSeedPhrase extends Component { onSubmit={this.handleOnSubmit} isLinkDrop={parseFundingOptions(this.props.location.search) !== null} hasSeedPhraseRecovery={hasSeedPhraseRecovery} - seedPhrase={seedPhrase} /> diff --git a/packages/frontend/src/utils/arrayUtils.js b/packages/frontend/src/utils/arrayUtils.js deleted file mode 100644 index dca48442e8..0000000000 --- a/packages/frontend/src/utils/arrayUtils.js +++ /dev/null @@ -1,3 +0,0 @@ -export const shuffleArray=(array) =>{ - return [...array].sort(() => Math.random() - 0.5); -};