diff --git a/packages/blockchain-wallet-v4-frontend/src/data/cache/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/data/cache/selectors.ts index 7f2100ed6a5..6420dc440bf 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/cache/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/cache/selectors.ts @@ -1,10 +1,11 @@ -import { path, prop } from 'ramda' +import { path } from 'ramda' import { crypto as wCrypto } from '@core' +import { RootState } from 'data/rootReducer' export const getLastAnnouncementState = (state): object | undefined => path(['cache', 'announcements'], state) -export const getCache = (state) => prop('cache', state) +export const getCache = (state: RootState) => state.cache export const getEmail = (state): string | undefined => path(['cache', 'lastEmail'], state) export const getExchangeEmail = (state): string | undefined => path(['cache', 'exchangeEmail'], state) diff --git a/packages/blockchain-wallet-v4-frontend/src/data/form/actions.ts b/packages/blockchain-wallet-v4-frontend/src/data/form/actions.ts index d710be7e67c..2b9015f6505 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/form/actions.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/form/actions.ts @@ -35,8 +35,3 @@ export { untouch, updateSyncErrors } from 'redux-form' - -export const change2 = (form, field, value) => ({ - payload: { field, form, value }, - type: AT.CHANGE2 -}) diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterEmail/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterEmail/index.tsx index 558471a0e54..cbcd1b0979d 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterEmail/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterEmail/index.tsx @@ -26,16 +26,11 @@ const LoginWrapper = styled(Wrapper)` ` const EnterEmail = (props: Props) => { - const { busy, formValues, invalid, magicLinkData, submitting, walletTabClicked } = props + const { busy, formValues, invalid, isMobilePlatform, submitting } = props return ( - + @@ -74,7 +69,7 @@ const EnterEmail = (props: Props) => { - + {isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterPassword/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterPassword/index.tsx index 4bdf125afa6..d31fe6b1a01 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterPassword/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/EnterPassword/index.tsx @@ -32,15 +32,13 @@ const LoginWrapper = styled(Wrapper)` const EnterPasswordExchange = (props: Props) => { const { - cache, exchangeError, formValues, handleBackArrowClickExchange, invalid, - magicLinkData, + isMobilePlatform, productAuthMetadata, - submitting, - walletTabClicked + submitting } = props const dispatch = useDispatch() @@ -62,20 +60,14 @@ const EnterPasswordExchange = (props: Props) => { return ( - + @@ -131,11 +123,10 @@ const EnterPasswordExchange = (props: Props) => { origin='PASSWORD' platform={productAuthMetadata.platform} product={ProductAuthOptions.EXCHANGE} - unified={cache.unifiedAccount} /> - + {isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/Institutional/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/Institutional/index.tsx index 976f57791fe..a540b9643b6 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/Institutional/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/Institutional/index.tsx @@ -48,7 +48,7 @@ const InstitutionalPortal = (props: Props) => { formValues, handleBackArrowClickExchange, invalid, - magicLinkData, + isMobilePlatform, productAuthMetadata, submitting } = props @@ -144,7 +144,7 @@ const InstitutionalPortal = (props: Props) => { /> - + {isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/TwoFA/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/TwoFA/index.tsx index 511b6cdd38a..d64553e7332 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/TwoFA/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Exchange/TwoFA/index.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from 'react' import { FormattedMessage } from 'react-intl' -import { useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { Field } from 'redux-form' import styled from 'styled-components' @@ -12,6 +12,7 @@ import FormLabel from 'components/Form/FormLabel' import TextBox from 'components/Form/TextBox' import { Wrapper } from 'components/Public' import { trackEvent } from 'data/analytics/slice' +import { getAuthType } from 'data/auth/selectors' import { ProductAuthOptions } from 'data/auth/types' import { Analytics, ExchangeErrorCodes } from 'data/types' import { required } from 'services/forms' @@ -33,14 +34,12 @@ const LoginWrapper = styled(Wrapper)` ` const TwoFAExchange = (props: Props) => { const { - authType, busy, - cache, exchangeError, formValues, handleBackArrowClickExchange, invalid, - magicLinkData, + isMobilePlatform, productAuthMetadata, submitting } = props @@ -48,6 +47,8 @@ const TwoFAExchange = (props: Props) => { const dispatch = useDispatch() + const authType = useSelector(getAuthType) + useEffect(() => { const twoFAType = getTwoFaType(authType) dispatch( @@ -69,7 +70,7 @@ const TwoFAExchange = (props: Props) => { formValues={formValues} handleBackArrowClick={handleBackArrowClickExchange} hideGuid - platform={magicLinkData?.platform_type} + hideBackArrow={isMobilePlatform} /> @@ -127,11 +128,10 @@ const TwoFAExchange = (props: Props) => { origin='2FA' platform={productAuthMetadata.platform} product={ProductAuthOptions.EXCHANGE} - unified={cache.unifiedAccount} /> - + {isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/ContinueOnMobile/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/ContinueOnMobile/index.tsx index 1102b136587..bb430b932fb 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/ContinueOnMobile/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/ContinueOnMobile/index.tsx @@ -1,15 +1,13 @@ import React from 'react' import { FormattedMessage } from 'react-intl' import { useDispatch } from 'react-redux' +import { push } from 'connected-react-router' import styled from 'styled-components' import { Badge, Button, Image, Text } from 'blockchain-info-components' import { Wrapper } from 'components/Public' -import { actions } from 'data' -import { isBrowserAndroid, isBrowserIOS } from 'services/browser' import { isMobile, media } from 'services/styles' -import { Props } from '../..' import { CircleBackground } from '../../model' const ContentWrapper = styled.div` @@ -37,14 +35,7 @@ const AppButtons = styled.footer` `}; ` -const ContinueOnMobile = (props: Props) => { - const dispatch = useDispatch() - // Add check here to make sure that there is wallet data - // route should navigate to login if there's no wallet data - const sofiWalletRedirect = () => { - dispatch(actions.router.push('/home')) - } - +const ContinueOnMobile = () => { const APP_URL = 'https://blockchainwallet.page.link/dashboard' const downloadMobileApp = () => { diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/Email/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/Email/index.tsx index 2b5e4ac2866..ebbdec07cd2 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/Email/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/Email/index.tsx @@ -17,6 +17,7 @@ import { media } from 'services/styles' import { Props } from '../..' import { ActionButton, LinkRow, LoginFormLabel, SoFiWrapperWithPadding } from '../../model' +import { push } from 'connected-react-router' const LoginWrapper = styled(Wrapper)` display: flex; @@ -43,7 +44,7 @@ const HelperText = styled(Text)` ` const Email = (props: Props) => { - const { busy, formValues, invalid, routerActions, submitting } = props + const { busy, formValues, invalid, submitting } = props const { sofiJwtPayload } = useSelector((state: RootState) => state.profile.sofiData).getOrElse( {} @@ -51,14 +52,14 @@ const Email = (props: Props) => { useEffect(() => { if (!sofiJwtPayload) { - routerActions.push('/sofi-error') + push('/sofi-error') } }, []) return ( - routerActions.push('/sofi')}> + push('/sofi')}> { +const SofiSuccess = () => { const dispatch = useDispatch() // Add check here to make sure that there is wallet data // route should navigate to login if there's no wallet data const sofiWalletRedirect = () => { - dispatch(actions.router.push('/home')) + dispatch(push('/home')) } const APP_URL = 'https://blockchainwallet.page.link/dashboard' diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/VerifySSN/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/VerifySSN/index.tsx index 7e8670ffdef..91d35433f3e 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/VerifySSN/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Sofi/VerifySSN/index.tsx @@ -11,17 +11,10 @@ import TextBox from 'components/Form/TextBox' import { Wrapper } from 'components/Public' import { actions } from 'data' import { Analytics } from 'data/types' -import { removeWhitespace } from 'services/forms/normalizers' import { media } from 'services/styles' import { Props } from '../..' -import { - ActionButton, - GuidError, - LinkRow, - LoginFormLabel, - SoFiWrapperWithPadding -} from '../../model' +import { ActionButton, LinkRow, LoginFormLabel, SoFiWrapperWithPadding } from '../../model' const LoginWrapper = styled(Wrapper)` display: flex; @@ -38,7 +31,7 @@ const FormBody = styled.div` ` const SofiVerifyID = (props: Props) => { - const { busy, formActions, formValues, invalid, submitting } = props + const { busy, formValues, invalid, submitting } = props const dispatch = useDispatch() diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/index.tsx index 3fb64d26616..a898216e140 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/index.tsx @@ -3,18 +3,17 @@ import React from 'react' import { getAuthorizeVerifyDevice } from 'data/auth/selectors' import { useRemote } from 'hooks' -import { Props } from '..' import Error from './template.error' import Loading from './template.loading' import Success from './template.success' -const VerifyMagicLink = (props: Props) => { +const VerifyMagicLink = () => { const { data, error, isLoading, isNotAsked } = useRemote(getAuthorizeVerifyDevice) if (isLoading || isNotAsked) return if (error) return - return + return } export default VerifyMagicLink diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/template.success.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/template.success.tsx index ad32cf2fd64..8b00f37df90 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/template.success.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/VerifyMagicLink/template.success.tsx @@ -1,20 +1,14 @@ import React from 'react' import { FormattedMessage } from 'react-intl' +import { useDispatch } from 'react-redux' import styled from 'styled-components' import { Banner, Button, Icon, Image, Text } from 'blockchain-info-components' -import { Wrapper } from 'components/Public' +import { actions } from 'data' import { media } from 'services/styles' -import { Props } from '..' import { LoginWrapper } from '../model' -const InfoWrapper = styled.div` - width: 100%; - text-align: left; - ${media.mobile` - text-align: center;`} -` const DeviceInfoWrapper = styled.div` margin-top: 20px; ` @@ -86,25 +80,28 @@ const SuccessWrapper = styled.div` flex-direction: column; ` -const Success = (props) => { - const { approver, requester } = props - return props.deviceAuthorized ? ( - - - - - - +const Success = ({ approver, deviceAuthorized, requester }) => { + const dispatch = useDispatch() + const authorizeDevice = (state: boolean) => dispatch(actions.auth.authorizeVerifyDevice(state)) - - - - - - ) : ( + if (deviceAuthorized) { + return ( + + + + + + + + + + ) + } + + return ( @@ -232,7 +229,7 @@ const Success = (props) => { props.authActions.authorizeVerifyDevice(true)} + onClick={() => authorizeDevice(true)} > @@ -242,7 +239,7 @@ const Success = (props) => { props.authActions.authorizeVerifyDevice(false)} + onClick={() => authorizeDevice(false)} > diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/CheckEmail/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/CheckEmail/index.tsx index 2f1af24c161..0919ea49cdf 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/CheckEmail/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/CheckEmail/index.tsx @@ -1,11 +1,13 @@ import React, { SyntheticEvent, useEffect, useState } from 'react' import { FormattedMessage } from 'react-intl' -import { useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import styled from 'styled-components' import { Button, Icon, Text } from 'blockchain-info-components' import { Wrapper } from 'components/Public' +import { selectAlerts } from 'data/alerts/selectors' import { trackEvent } from 'data/analytics/slice' +import { getIsSofi } from 'data/auth/selectors' import { Analytics, LoginSteps } from 'data/types' import { VERIFY_EMAIL_SENT_ERROR } from 'services/alerts' import { media } from 'services/styles' @@ -41,6 +43,15 @@ const CheckEmail = (props: Props) => { const dispatch = useDispatch() + const isSofi = useSelector(getIsSofi) + const alerts = useSelector(selectAlerts) + + const onResendEmail = (e: SyntheticEvent) => { + setDisabled(true) + setSentState('sent') + props.handleSubmit(e) + } + useEffect(() => { if (disabled) { setTimeout(() => { @@ -63,22 +74,20 @@ const CheckEmail = (props: Props) => { ) }, []) - const hasErrorAlert = props.alerts.find((alert) => alert.message === VERIFY_EMAIL_SENT_ERROR) + const hasErrorAlert = alerts.find((alert) => alert.message === VERIFY_EMAIL_SENT_ERROR) + + const handleBackClick = () => { + if (isSofi) { + props.setStep(LoginSteps.SOFI_EMAIL) + } else { + props.handleBackArrowClickWallet() + } + } return ( - { - if (props.isSofi) { - props.setStep(LoginSteps.SOFI_EMAIL) - } else { - props.handleBackArrowClickWallet() - } - }} - product={props.productAuthMetadata.product} - /> + @@ -113,11 +122,7 @@ const CheckEmail = (props: Props) => { data-e2e='loginResendEmail' disabled={disabled && !hasErrorAlert} // @ts-ignore - onClick={(e: SyntheticEvent) => { - setDisabled(true) - setSentState('sent') - props.handleSubmit(e) - }} + onClick={onResendEmail} > {disabled && sentState === 'sent' && !hasErrorAlert && ( @@ -144,7 +149,7 @@ const CheckEmail = (props: Props) => { )} - + {props.isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterEmailOrGuid/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterEmailOrGuid/index.tsx index c7d750e7147..2a6f0224538 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterEmailOrGuid/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterEmailOrGuid/index.tsx @@ -9,7 +9,6 @@ import FormGroup from 'components/Form/FormGroup' import FormItem from 'components/Form/FormItem' import TextBox from 'components/Form/TextBox' import { Wrapper } from 'components/Public' -import { ProductAuthOptions } from 'data/types' import { required, validWalletIdOrEmail } from 'services/forms' import { removeWhitespace } from 'services/forms/normalizers' import { media } from 'services/styles' @@ -29,13 +28,12 @@ const LoginWrapper = styled(Wrapper)` ` const EnterEmailOrGuid = (props: Props) => { - const { busy, exchangeTabClicked, formValues, invalid, magicLinkData, submitting, walletError } = - props + const { busy, formValues, invalid, isMobilePlatform, submitting, walletError } = props const guidError = walletError?.toLowerCase().includes('unknown wallet id') return ( - + @@ -94,7 +92,7 @@ const EnterEmailOrGuid = (props: Props) => { - + {isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterPassword/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterPassword/index.tsx index 45d03271362..3170d75bf2a 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterPassword/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/EnterPassword/index.tsx @@ -12,7 +12,9 @@ import FormLabel from 'components/Form/FormLabel' import PasswordBox from 'components/Form/PasswordBox' import { Wrapper } from 'components/Public' import QRCodeWrapper from 'components/QRCodeWrapper' +import { getIsSofi } from 'data/auth/selectors' import { getChannelPrivKeyForQrData } from 'data/cache/selectors' +import { getInitialRedirect } from 'data/goals/selectors' import { ProductAuthOptions, UnifiedAccountRedirectType } from 'data/types' import { required } from 'services/forms' import { isMobile, media } from 'services/styles' @@ -74,19 +76,17 @@ const SettingsGoalText = styled.div` const EnterPasswordWallet = (props: OwnProps) => { const { busy, - exchangeTabClicked, formValues, handleBackArrowClickWallet, - initialRedirect, invalid, - isSofi, - magicLinkData, + isMobilePlatform, productAuthMetadata, submitting, walletError } = props const qrData = useSelector(getChannelPrivKeyForQrData) + const isSofi = useSelector(getIsSofi) const passwordError = walletError?.toLowerCase().includes('wrong_wallet_password') const accountLocked = @@ -94,23 +94,21 @@ const EnterPasswordWallet = (props: OwnProps) => { (walletError.toLowerCase().includes('this account has been locked') || walletError.toLowerCase().includes('account is locked') || walletError.toLowerCase().includes('account deactivated')) + + const initialRedirect = useSelector(getInitialRedirect) as UnifiedAccountRedirectType + const settingsRedirect = Object.values(UnifiedAccountRedirectType).includes(initialRedirect) return ( - {!settingsRedirect && !isSofi && ( - - )} + {!settingsRedirect && !isSofi && } {!settingsRedirect && ( )} diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/TwoFA/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/TwoFA/index.tsx index ffbb8b929ed..41508723c03 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/TwoFA/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/Wallet/TwoFA/index.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from 'react' import { FormattedMessage } from 'react-intl' -import { useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { LinkContainer } from 'react-router-bootstrap' import { Field } from 'redux-form' import styled from 'styled-components' @@ -15,6 +15,7 @@ import TextBox from 'components/Form/TextBox' import { Wrapper } from 'components/Public' import { auth } from 'data/actions' import { trackEvent } from 'data/analytics/slice' +import { getAuthType } from 'data/auth/selectors' import { ProductAuthOptions } from 'data/auth/types' import { Analytics, ExchangeErrorCodes } from 'data/types' import { required } from 'services/forms' @@ -45,18 +46,19 @@ const ResponsiveRow = styled(Row)` const TwoFAWallet = (props: Props) => { const { - authType, busy, exchangeError, formValues, handleBackArrowClickWallet, invalid, - magicLinkData, + isMobilePlatform, productAuthMetadata, submitting, walletError } = props + const authType = useSelector(getAuthType) + const accountLocked = walletError?.toLowerCase().includes('this account has been locked') || walletError?.toLowerCase().includes('account is locked') || @@ -95,8 +97,7 @@ const TwoFAWallet = (props: Props) => { formValues={formValues} handleBackArrowClick={handleBackArrowClickWallet} marginTop='28px' - platform={magicLinkData?.platform_type} - product={props.productAuthMetadata.product} + hideBackArrow={isMobilePlatform} /> {twoFAType && ( @@ -188,7 +189,7 @@ const TwoFAWallet = (props: Props) => { /> - + {!isMobilePlatform && } ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/BackArrowHeader/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/BackArrowHeader/index.tsx index 55ccdb55ba9..2e220ff716a 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/BackArrowHeader/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/BackArrowHeader/index.tsx @@ -1,9 +1,11 @@ import React from 'react' import { FormattedMessage } from 'react-intl' +import { useSelector } from 'react-redux' import styled from 'styled-components' import { Icon, Text } from 'blockchain-info-components' -import { LoginFormType, LoginSteps, PlatformTypes, ProductAuthOptions } from 'data/auth/types' +import { getProduct } from 'data/auth/selectors' +import { LoginFormType, LoginSteps, ProductAuthOptions } from 'data/auth/types' import { isMobile } from 'services/styles' const BackArrowWrapper = styled.div<{ hideBackArrow?: boolean; marginTop?: string }>` @@ -27,28 +29,25 @@ const EmailAndGuid = styled.div` type Props = { formValues: LoginFormType handleBackArrowClick: () => void + hideBackArrow?: boolean hideGuid?: boolean marginTop?: string - platform?: PlatformTypes - product?: ProductAuthOptions } const BackArrowHeader = ({ formValues, handleBackArrowClick, + hideBackArrow, hideGuid, - marginTop, - platform, - product + marginTop }: Props) => { - const isExchangeLogin = product === ProductAuthOptions.EXCHANGE - const email = isExchangeLogin - ? formValues.exchangeEmail - : formValues.email || formValues.sofiLoginEmail + const activeProduct = useSelector(getProduct) + const isExchangeLogin = activeProduct === ProductAuthOptions.EXCHANGE + const walletEmail = formValues.email ?? formValues.sofiLoginEmail + const email = isExchangeLogin ? formValues.exchangeEmail : walletEmail const guid = formValues?.guid const firstPartGuid = guid?.slice(0, 4) const lastPartGuid = guid?.slice(-4) - const hideBackArrow = platform === PlatformTypes.ANDROID || platform === PlatformTypes.IOS return ( {!hideBackArrow && ( diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/NeedHelpLink/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/NeedHelpLink/index.tsx index 7d0939cf863..371592da796 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/NeedHelpLink/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/NeedHelpLink/index.tsx @@ -1,16 +1,19 @@ import React from 'react' import { FormattedMessage } from 'react-intl' -import { useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { LinkContainer } from 'react-router-bootstrap' import { Link } from 'blockchain-info-components' import { trackEvent } from 'data/analytics/slice' import { Analytics } from 'data/analytics/types' +import { getUnifiedAccountStatus } from 'data/cache/selectors' import { PlatformTypes, ProductAuthOptions } from 'data/types' -const NeedHelpLink = ({ origin, platform, product, unified }: Props) => { +const NeedHelpLink = ({ origin, platform, product }: Props) => { const dispatch = useDispatch() + const unified = useSelector(getUnifiedAccountStatus) + const onClick = () => { dispatch( trackEvent({ @@ -40,7 +43,6 @@ type Props = { origin: string platform?: PlatformTypes product: ProductAuthOptions - unified?: boolean } export default NeedHelpLink diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/ProductTabMenu/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/ProductTabMenu/index.tsx index b721c4668f6..aed8e768266 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/ProductTabMenu/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/ProductTabMenu/index.tsx @@ -1,9 +1,15 @@ import React from 'react' import { FormattedMessage } from 'react-intl' +import { useDispatch, useSelector } from 'react-redux' +import { push } from 'connected-react-router' import styled from 'styled-components' import { Image, Text } from 'blockchain-info-components' -import { PlatformTypes, ProductAuthOptions } from 'data/auth/types' +import { actions } from 'data' +import { LOGIN_FORM } from 'data/auth/model' +import { getProduct } from 'data/auth/selectors' +import { LoginSteps, ProductAuthOptions } from 'data/auth/types' +import { getCache } from 'data/cache/selectors' const TabWrapper = styled.div` display: flex; @@ -34,30 +40,49 @@ const ProductIcon = styled(Image)` ` const ProductTabMenu = ({ - active, - onExchangeTabClick, - onWalletTabClick, - platform, + isMobilePlatform, product }: { - active: ProductAuthOptions - onExchangeTabClick?: () => void - onWalletTabClick?: () => void - platform?: PlatformTypes + isMobilePlatform?: boolean product?: ProductAuthOptions }) => { - const isWalletActive = active === ProductAuthOptions.WALLET + const dispatch = useDispatch() + const { exchangeEmail, guidStored, lastEmail, lastGuid } = useSelector(getCache) + const activeProduct = useSelector(getProduct) + + const exchangeTabClick = () => { + dispatch(actions.auth.setProductAuthMetadata({ product: ProductAuthOptions.EXCHANGE })) + if (exchangeEmail) { + actions.form.change(LOGIN_FORM, 'exchangeEmail', exchangeEmail) + actions.form.change(LOGIN_FORM, 'step', LoginSteps.ENTER_PASSWORD_EXCHANGE) + } else { + actions.form.change(LOGIN_FORM, 'step', LoginSteps.ENTER_EMAIL_GUID) + } + dispatch(push('/login?product=exchange')) + } + + const walletTabClick = () => { + dispatch(actions.auth.setProductAuthMetadata({ product: ProductAuthOptions.WALLET })) + if (guidStored || lastGuid) { + actions.form.change(LOGIN_FORM, 'guid', lastGuid || guidStored) + actions.form.change(LOGIN_FORM, 'email', lastEmail) + actions.form.change(LOGIN_FORM, 'step', LoginSteps.ENTER_PASSWORD_WALLET) + } else { + actions.form.change(LOGIN_FORM, 'step', LoginSteps.ENTER_EMAIL_GUID) + } + dispatch(push('/login?product=wallet')) + } + + const isWalletActive = activeProduct === ProductAuthOptions.WALLET // if webview is being opened from exchange mobile app // want to hide the wallet tab - const hideWalletTab = - (platform === PlatformTypes.ANDROID || platform === PlatformTypes.IOS) && - product === ProductAuthOptions.EXCHANGE + const hideWalletTab = isMobilePlatform && product === ProductAuthOptions.EXCHANGE return ( {!hideWalletTab && ( diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/SignupLink/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/SignupLink/index.tsx index 5bb0a99d6e0..4ce16bc4be6 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/SignupLink/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/components/SignupLink/index.tsx @@ -4,7 +4,6 @@ import { LinkContainer } from 'react-router-bootstrap' import styled from 'styled-components' import { Text } from 'blockchain-info-components' -import { PlatformTypes } from 'data/types' import { media } from 'services/styles' const SubCard = styled.div` @@ -37,9 +36,7 @@ const Row = styled.div` `} ` -const SignUpLink = ({ platform }: { platform?: PlatformTypes }) => { - if (platform === PlatformTypes.ANDROID || platform === PlatformTypes.IOS) return null - +const SignUpLink = () => { return ( diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.tsx index d4c539ec461..5f2150699d4 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.tsx @@ -1,21 +1,27 @@ -import React, { PureComponent } from 'react' -import { connect, ConnectedProps } from 'react-redux' -import { bindActionCreators, compose } from 'redux' -import { InjectedFormProps, reduxForm } from 'redux-form' +import React, { useEffect } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { getFormValues, reduxForm } from 'redux-form' import { RemoteDataType } from '@core/types' import Form from 'components/Form/Form' -import { actions, selectors } from 'data' +import { auth as authActions, cache as cacheActions } from 'data/actions' +import { trackEvent } from 'data/analytics/slice' import { LOGIN_FORM } from 'data/auth/model' import { - AlertsState, + getExchangeLogin, + getLogin, + getMagicLinkData, + getProductAuthMetadata +} from 'data/auth/selectors' +import { getCache } from 'data/cache/selectors' +import { Analytics, ExchangeErrorCodes, LoginFormType, LoginSteps, PlatformTypes, - ProductAuthOptions, - UnifiedAccountRedirectType + ProductAuthMetadata, + ProductAuthOptions } from 'data/types' import UrlNoticeBar from './components/UrlNoticeBar' @@ -23,7 +29,6 @@ import ExchangeEnterEmail from './Exchange/EnterEmail' import EnterPasswordExchange from './Exchange/EnterPassword' import InstitutionalPortal from './Exchange/Institutional' import TwoFAExchange from './Exchange/TwoFA' -import { getData } from './selectors' // SOFI Login import Email from './Sofi/Email' import SofiSuccess from './Sofi/Success' @@ -34,230 +39,184 @@ import WalletEnterEmailOrGuid from './Wallet/EnterEmailOrGuid' import EnterPasswordWallet from './Wallet/EnterPassword' import TwoFAWallet from './Wallet/TwoFA' -class Login extends PureComponent & Props> { - componentDidMount() { - this.props.authActions.initializeLogin() - if (window?._SardineContext) { - window._SardineContext.updateConfig({ - flow: 'LOGIN' - }) - } - this.props.analyticsActions.trackEvent({ - key: Analytics.LOGIN_VIEWED, - properties: { - device_origin: this.props?.productAuthMetadata?.platform || 'WEB', - originalTimestamp: new Date().toISOString() - } - }) - } - - setStep = (step: LoginSteps) => { - this.props.formActions.change(LOGIN_FORM, 'step', step) - } - - handleBackArrowClick = () => { - const { authActions, formActions } = this.props - formActions.destroy(LOGIN_FORM) - this.setStep(LoginSteps.ENTER_EMAIL_GUID) - authActions.clearLoginError() - } - - handleBackArrowClickWallet = () => { - this.handleBackArrowClick() - this.props.cacheActions.removeWalletLogin() - if (this.props.cache.unifiedAccount) { - this.props.cacheActions.removeExchangeLogin() - } - } - - handleBackArrowClickExchange = () => { - this.handleBackArrowClick() - this.props.cacheActions.removeExchangeLogin() - if (this.props.cache.unifiedAccount) { - this.props.cacheActions.removeWalletLogin() - } +const Login = (props) => { + const { change, destroy, ...reduxFormProps } = props + const formActions = { change, destroy } + + // Used here + const cache = useSelector(getCache) + const exchangeLoginDataR = useSelector(getExchangeLogin) as RemoteDataType + const formValues = useSelector(getFormValues(LOGIN_FORM)) as LoginFormType + const magicLinkMetadata = useSelector(getMagicLinkData) + const productAuthMetadata = useSelector(getProductAuthMetadata) + const walletLoginDataR = useSelector(getLogin) as RemoteDataType + + const dispatch = useDispatch() + + const { step } = formValues || LoginSteps.ENTER_EMAIL_GUID + + const { exchangeError } = exchangeLoginDataR.cata({ + Failure: (val) => ({ busy: false, exchangeError: val }), + Loading: () => ({ busy: true, exchangeError: null }), + NotAsked: () => ({ busy: false, exchangeError: null }), + Success: () => ({ busy: false, exchangeError: null }) + }) + + const { busy, walletError } = walletLoginDataR.cata({ + Failure: (val) => ({ busy: false, walletError: val }), + Loading: () => ({ busy: true, walletError: null }), + NotAsked: () => ({ busy: false, walletError: null }), + Success: () => ({ busy: false, walletError: null }) + }) + + const handleBackArrowClick = () => { + formActions.destroy() + formActions.change('step', LoginSteps.ENTER_EMAIL_GUID) + dispatch(authActions.clearLoginError()) } - exchangeTabClicked = () => { - const { exchangeEmail } = this.props.cache - const { authActions, formActions, routerActions } = this.props - authActions.setProductAuthMetadata({ product: ProductAuthOptions.EXCHANGE }) - routerActions.push('/login?product=exchange') - if (exchangeEmail) { - formActions.change(LOGIN_FORM, 'exchangeEmail', exchangeEmail) - formActions.change(LOGIN_FORM, 'step', LoginSteps.ENTER_PASSWORD_EXCHANGE) - } else { - formActions.change(LOGIN_FORM, 'step', LoginSteps.ENTER_EMAIL_GUID) + const handleBackArrowClickWallet = () => { + handleBackArrowClick() + dispatch(cacheActions.removeWalletLogin()) + if (cache.unifiedAccount) { + dispatch(cacheActions.removeExchangeLogin()) } } - walletTabClicked = () => { - const { guidStored, lastEmail, lastGuid } = this.props.cache - const { authActions, formActions, routerActions } = this.props - authActions.setProductAuthMetadata({ product: ProductAuthOptions.WALLET }) - routerActions.push('/login?product=wallet') - if (guidStored || lastGuid) { - formActions.change(LOGIN_FORM, 'guid', lastGuid || guidStored) - formActions.change(LOGIN_FORM, 'email', lastEmail) - formActions.change(LOGIN_FORM, 'step', LoginSteps.ENTER_PASSWORD_WALLET) - } else { - formActions.change(LOGIN_FORM, 'step', LoginSteps.ENTER_EMAIL_GUID) + const handleBackArrowClickExchange = () => { + handleBackArrowClick() + dispatch(cacheActions.removeExchangeLogin()) + if (cache.unifiedAccount) { + dispatch(cacheActions.removeWalletLogin()) } } - handleSubmit = (e) => { + const handleSubmit = (e) => { e.preventDefault() - this.props.authActions.continueLoginProcess() + dispatch(authActions.continueLoginProcess()) } - render() { - const { exchangeLoginDataR, formValues, productAuthMetadata, walletLoginDataR } = this.props - const { platform, product } = productAuthMetadata - const { step } = formValues || LoginSteps.ENTER_EMAIL_GUID - - const { exchangeError } = exchangeLoginDataR.cata({ - Failure: (val) => ({ busy: false, exchangeError: val }), - Loading: () => ({ busy: true, exchangeError: null }), - NotAsked: () => ({ busy: false, exchangeError: null }), - Success: () => ({ busy: false, exchangeError: null }) - }) + const isPlatformMobile = [PlatformTypes.ANDROID, PlatformTypes.IOS].includes( + productAuthMetadata.platform as PlatformTypes + ) + + const isMagicLinkMobile = [PlatformTypes.ANDROID, PlatformTypes.IOS].includes( + magicLinkMetadata?.platform_type as PlatformTypes + ) + + const loginProps = { + ...reduxFormProps, + busy, // TODO see if we still need busy + exchangeError, + formValues, + handleBackArrowClickExchange, + handleBackArrowClickWallet, + isMobilePlatform: isMagicLinkMobile, + productAuthMetadata, + walletError + } - const { busy, walletError } = walletLoginDataR.cata({ - Failure: (val) => ({ busy: false, walletError: val }), - Loading: () => ({ busy: true, walletError: null }), - NotAsked: () => ({ busy: false, walletError: null }), - Success: () => ({ busy: false, walletError: null }) - }) + useEffect(() => { + dispatch(authActions.initializeLogin()) - const loginProps = { - busy, // TODO see if we still need busy - exchangeError, - exchangeTabClicked: this.exchangeTabClicked, - isMobileViewLogin: platform === PlatformTypes.ANDROID || platform === PlatformTypes.IOS, - walletError, - ...this.props, - handleBackArrowClickExchange: this.handleBackArrowClickExchange, - handleBackArrowClickWallet: this.handleBackArrowClickWallet, - setStep: this.setStep, - walletTabClicked: this.walletTabClicked + if (window?._SardineContext) { + window._SardineContext.updateConfig({ + flow: 'LOGIN' + }) } - const { isMobileViewLogin } = loginProps - - return ( - <> - {/* CONTENT */} -
- {(() => { - switch (step) { - case LoginSteps.SOFI_EMAIL: - return - case LoginSteps.INSTITUTIONAL_PORTAL: - return - case LoginSteps.ENTER_PASSWORD_EXCHANGE: - return ( - <> - {!isMobileViewLogin && } - - - ) - case LoginSteps.ENTER_PASSWORD_WALLET: - return ( - <> - {!isMobileViewLogin && } - - - ) - case LoginSteps.TWO_FA_EXCHANGE: - return ( - <> - {!isMobileViewLogin && } - - - ) - case LoginSteps.TWO_FA_WALLET: - return ( - <> - {!isMobileViewLogin && } - - - ) - case LoginSteps.SOFI_VERIFY_ID: - return - case LoginSteps.CHECK_EMAIL: - return - case LoginSteps.VERIFY_MAGIC_LINK: - return - case LoginSteps.SOFI_SUCCESS: - return - - case LoginSteps.ENTER_EMAIL_GUID: - default: - return product === ProductAuthOptions.EXCHANGE ? ( - <> - {!isMobileViewLogin && } - - - ) : ( - <> - {!isMobileViewLogin && } - - - ) - } - })()} - - + dispatch( + trackEvent({ + key: Analytics.LOGIN_VIEWED, + properties: { + device_origin: productAuthMetadata?.platform ?? 'WEB', + originalTimestamp: new Date().toISOString() + } + }) ) - } + }, []) + + return ( +
+ {(() => { + switch (step) { + case LoginSteps.SOFI_EMAIL: + return + case LoginSteps.INSTITUTIONAL_PORTAL: + return + case LoginSteps.ENTER_PASSWORD_EXCHANGE: + return ( + <> + {!isPlatformMobile && } + + + ) + case LoginSteps.ENTER_PASSWORD_WALLET: + return ( + <> + {!isPlatformMobile && } + + + ) + case LoginSteps.TWO_FA_EXCHANGE: + return ( + <> + {!isPlatformMobile && } + + + ) + case LoginSteps.TWO_FA_WALLET: + return ( + <> + {!isPlatformMobile && } + + + ) + case LoginSteps.SOFI_VERIFY_ID: + return + case LoginSteps.CHECK_EMAIL: + return + case LoginSteps.VERIFY_MAGIC_LINK: + return + case LoginSteps.SOFI_SUCCESS: + return + + case LoginSteps.ENTER_EMAIL_GUID: + default: { + const LoginComponent = + productAuthMetadata.product === ProductAuthOptions.EXCHANGE + ? ExchangeEnterEmail + : WalletEnterEmailOrGuid + + return ( + <> + {!isPlatformMobile && } + + + ) + } + } + })()} + + ) } -const mapStateToProps = (state) => ({ - accountUnificationFlow: selectors.auth.getAccountUnificationFlowType(state), - alerts: selectors.alerts.selectAlerts(state) as AlertsState, - authType: selectors.auth.getAuthType(state) as number, - cache: selectors.cache.getCache(state), - data: getData(state), - exchangeLoginDataR: selectors.auth.getExchangeLogin(state) as RemoteDataType, - formValues: selectors.form.getFormValues(LOGIN_FORM)(state) as LoginFormType, - initialRedirect: selectors.goals.getInitialRedirect(state) as UnifiedAccountRedirectType, - initialValues: { - step: LoginSteps.ENTER_EMAIL_GUID - }, - isSofi: selectors.auth.getIsSofi(state), - jwtToken: selectors.auth.getJwtToken(state), - magicLinkData: selectors.auth.getMagicLinkData(state), - productAuthMetadata: selectors.auth.getProductAuthMetadata(state), - walletLoginDataR: selectors.auth.getLogin(state) as RemoteDataType -}) - -const mapDispatchToProps = (dispatch) => ({ - analyticsActions: bindActionCreators(actions.analytics, dispatch), - authActions: bindActionCreators(actions.auth, dispatch), - cacheActions: bindActionCreators(actions.cache, dispatch), - formActions: bindActionCreators(actions.form, dispatch), - routerActions: bindActionCreators(actions.router, dispatch) -}) - -const connector = connect(mapStateToProps, mapDispatchToProps) - -type OwnProps = { +export type Props = { busy?: boolean exchangeError?: ExchangeErrorCodes exchangeTabClicked?: () => void + formValues: LoginFormType handleBackArrowClickExchange: () => void handleBackArrowClickWallet: () => void - invalid: boolean - isMobileViewLogin?: boolean - pristine: boolean - setStep: (step: LoginSteps) => void + invalid?: boolean + isMobilePlatform: boolean + pristine?: boolean + productAuthMetadata: ProductAuthMetadata submitting: boolean walletError?: string - walletTabClicked?: () => void } -export type Props = ConnectedProps & OwnProps - -const enhance = compose(reduxForm({ form: LOGIN_FORM }), connector) - -export default enhance(Login) +export default reduxForm({ + form: LOGIN_FORM, + initialValues: { step: LoginSteps.ENTER_EMAIL_GUID } +})(Login) diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/model.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/model.tsx index 06a0ae3c6f4..11f1867fc4b 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/model.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/model.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components' -import { Button, SpinningLoader, TextGroup } from 'blockchain-info-components' +import { Button, TextGroup } from 'blockchain-info-components' import FormLabel from 'components/Form/FormLabel' import { Wrapper } from 'components/Public' import { media } from 'services/styles' @@ -26,13 +26,6 @@ export const ActionButton = styled(Button)` export const Row = styled.div` display: flex; ` -export const CenterRow = styled.div` - display: flex; - justify-content: center; -` -export const CartridgeSentContainer = styled.div` - width: auto; -` export const GuidError = styled(TextGroup)` display: inline; margin-top: 3px; @@ -51,30 +44,11 @@ export const CircleBackground = styled.div<{ color?: string; size?: string }>` border-radius: ${(props) => (props.size ? props.size : '40px')}; margin-bottom: 8px; ` -export const RectangleBackground = styled.div` - height: 48px; - width: 100%; - background-color: ${(props) => props.theme.grey000}; - border-radius: 8px; - margin-top: 24px; -` -export const HelpRow = styled.div` - display: flex; - justify-content: space-between; - padding: 16px; -` -export const Column = styled.div` +export const CenteredColumn = styled.div` display: flex; flex-direction: column; -` -export const CenteredColumn = styled(Column)` align-items: center; ` -export const Loader = styled(SpinningLoader)` - height: 75px; - width: 75px; - margin: 75px; -` export const LinkRow = styled.div` display: flex; flex-direction: column; diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/selectors.ts deleted file mode 100644 index 69969de0c53..00000000000 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/selectors.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { lift } from 'ramda' - -import { ExtractSuccess } from '@core/types' -import { selectors } from 'data' -import { LOGIN_FORM } from 'data/auth/model' -import { RootState } from 'data/rootReducer' -import { LoginFormType } from 'data/types' - -export const getData = (state: RootState) => { - const accountUnificationFlow = selectors.auth.getAccountUnificationFlowType(state) - const authType = selectors.auth.getAuthType(state) - const formValues = selectors.form.getFormValues(LOGIN_FORM)(state) as LoginFormType - const exchangeLoginR = selectors.auth.getExchangeLogin(state) - const jwtToken = selectors.auth.getJwtToken(state) - const language = selectors.preferences.getLanguage(state) - const magicLinkData = selectors.auth.getMagicLinkData(state) - const productAuthMetadata = selectors.auth.getProductAuthMetadata(state) - const walletLoginR = selectors.auth.getLogin(state) - - return lift( - ( - exchangeLogin: ExtractSuccess, - walletLogin: ExtractSuccess - ) => ({ - accountUnificationFlow, - authType, - exchangeLogin, - formValues, - jwtToken, - language, - magicLinkData, - productAuthMetadata, - walletLogin - }) - )(exchangeLoginR, walletLoginR) -} diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/utils.ts b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/utils.ts index 4bef7b908de..b3a7bf44560 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/utils.ts +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/utils.ts @@ -1,4 +1,4 @@ -export const getTwoFaType = (authType: number): string | null => { +export const getTwoFaType = (authType: number) => { if (authType > 0) { if (authType === 1) return 'YUBIKEY' if (authType === 4 || authType === 5) return 'SMS'