Skip to content

Commit

Permalink
chore(merge): development
Browse files Browse the repository at this point in the history
  • Loading branch information
schnogz committed Jul 23, 2021
2 parents bee9b85 + 80fbf3b commit 350c8d1
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,8 @@ type MessagesType = {
'modals.onboarding.linktoexchangeaccount.na.subtitle-1': "There's a new way to trade. Link your Wallet for instant access. "
'modals.onboarding.linktoexchangeaccount.success.subtitle-1': 'Your Blockchain Wallet is now connected to Exchange!'
'modals.onboarding.linktoexchangeaccount.success.title': 'Success!'
'modals.nabuuserconflict.title': 'Your Trading Account is linked to another wallet'
'modals.nabuuserconflict.body': 'Your Blockchain.com trading account is associated with another wallet. Please log into your wallet starting with {placeholder} for account access.'
'modals.pairingcode.title': 'Pairing Code'
'modals.prompt.button': 'Submit'
'modals.qrcode.scan': 'Scan QR Code'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,38 @@ export default ({ api, coreSagas, networks }) => {
} catch (e) {
return yield put(A.setStepsFailure(e))
}
const tiers = (yield select(selectors.modules.profile.getUserTiers)).getOrElse({
let tiers = (yield select(selectors.modules.profile.getUserTiers)).getOrElse({
next: 0,
selected: 2
})
const kycState = (selectors.modules.profile.getUserKYCState(yield select()) as RemoteDataType<
string,
KycStateType
>).getOrElse('NONE')
// Case where user recovers their wallet with mnemonic
// and we reset their KYC. We have to force next and
// selected into certain states to reliably send user
// through correct reverification flow
const kycDocResubmissionStatus = (yield select(
selectors.modules.profile.getKycDocResubmissionStatus
)).getOrElse({})
const tiersState = (yield select(selectors.modules.profile.getTiers)).getOrElse({})
if (kycDocResubmissionStatus === 1) {
if (tiers.current === 0) {
// case where user already went through first step
// of verfication but was rejected, want to set
// next to 2
if (tiersState[0].state === 'rejected') {
tiers = { current: 0, next: 2, selected: 2 }
} else {
tiers = { current: 0, next: 1, selected: 2 }
}
} else if (tiers.current === 1 || tiers.current === 3) {
tiers = { current: 1, next: 2, selected: 2 }
} else {
return
}
}
const steps = computeSteps({
kycState,
needMoreInfo,
Expand Down Expand Up @@ -454,16 +478,16 @@ export default ({ api, coreSagas, networks }) => {
goToPrevStep,
initializeStep,
initializeVerification,
registerUserCampaign,
resendSmsCode,
registerUserCampaign,
saveInfoAndResidentialData,
selectTier,
sendDeeplink,
sendEmailVerification,
updateEmail,
updateSmsNumber,
updateSmsStep,
updateSmsNumber,
verifyIdentity,
verifySmsNumber
verifySmsNumber,
updateEmail
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,11 @@ export default ({ api, coreSagas, networks }) => {
))
.map(anyPass([equals(GENERAL), equals(EXPIRED)]))
.getOrElse(false)

if (showKycDocResubmitModal) {
// check if user is under review. resubmission status sometimes only
// is removed from user profile after they are verified
const kycState = (yield select(selectors.modules.profile.getUserKYCState)).getOrElse('NONE')
const isKycPending = kycState === KYC_STATES.UNDER_REVIEW || kycState === KYC_STATES.PENDING
if (showKycDocResubmitModal && !isKycPending) {
yield put(
actions.goals.addInitialModal('kycDocResubmit', 'KYC_RESUBMIT_MODAL', {
origin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export enum ModalName {
MOBILE_NUMBER_ADD_MODAL = 'MOBILE_NUMBER_ADD_MODAL',
MOBILE_NUMBER_CHANGE_MODAL = 'MOBILE_NUMBER_CHANGE_MODAL',
MOBILE_NUMBER_VERIFY_MODAL = 'MOBILE_NUMBER_VERIFY_MODAL',
NABU_USER_CONFLICT_REDIRECT = 'NABU_USER_CONFLICT_REDIRECT',
PAIRING_CODE_MODAL = 'PAIRING_CODE_MODAL',
PROMPT_INPUT_MODAL = 'PROMPT_INPUT_MODAL',
QR_CODE_MODAL = 'QR_CODE_MODAL',
Expand Down Expand Up @@ -88,6 +89,7 @@ export type ModalOriginType =
| 'KycDocResubmitGoal'
| 'KycRequiredStep'
| 'LoginSaga'
| 'NabuUserAuth'
| 'PaymentProtocolGoal'
| 'PendingOrder'
| 'PriceChart'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ export default ({ api, coreSagas, networks }) => {
const expiresIn = moment(expiresAt).subtract(5, 's').diff(moment())
yield spawn(renewSession, userId, lifetimeToken, email, guid, expiresIn)
} catch (e) {
if (prop('description', e) === userRequiresRestoreError) {
return yield call(recoverUser)
if (prop('status', e) === 409) {
throw new Error(e.description)
}
throw e
}
Expand All @@ -181,6 +181,15 @@ export default ({ api, coreSagas, networks }) => {
yield call(setSession, userId, lifetimeToken, email, guid)
} catch (e) {
yield put(A.setApiTokenFailure(e))
if (e.message.includes('User linked to another wallet')) {
return yield put(
actions.modals.showModal(
'NABU_USER_CONFLICT_REDIRECT',
{ origin: 'NabuUserAuth' },
{ errorMessage: e.message }
)
)
}
yield spawn(renewSession, userId, lifetimeToken, email, guid, authRetryDelay)
}
}
Expand Down Expand Up @@ -293,15 +302,7 @@ export default ({ api, coreSagas, networks }) => {
state: 'NONE'
} as UserDataType)
/* eslint-disable */
const {
id,
address,
mobile,
mobileVerified,
state,
kycState,
...userData
} = user
const { id, address, mobile, mobileVerified, state, kycState, ...userData } = user
/* eslint-enable */
const updatedData = { ...userData, ...data }

Expand Down Expand Up @@ -397,59 +398,43 @@ export default ({ api, coreSagas, networks }) => {
yield delay(10000)
/* eslint-disable */
attemptCount++
/* eslint-disable */
/* eslint-disable */
// if 5 minutes has passed, cancel poll and mark as timeout
if (equals(30, attemptCount)) {
yield put(
A.linkToExchangeAccountFailure(
'Timeout waiting for account connection status.'
)
)
yield put(A.linkToExchangeAccountFailure('Timeout waiting for account connection status.'))
return
}
yield call(fetchUser)
const isExchangeAccountLinked = (yield select(
S.isExchangeAccountLinked
)).getOrElse(false)
const isExchangeAccountLinked = (yield select(S.isExchangeAccountLinked)).getOrElse(false)
if (isExchangeAccountLinked) {
yield put(A.linkToExchangeAccountSuccess())
} else {
yield call(pollForAccountLinkSuccess, attemptCount)
}
} catch (e) {
yield put(
A.linkToExchangeAccountFailure(
'Unable to check current account status.'
)
)
yield put(A.linkToExchangeAccountFailure('Unable to check current account status.'))
}
}

const linkToExchangeAccount = function * ({ payload }) {
const linkToExchangeAccount = function* ({ payload }) {
try {
const { utmCampaign } = payload
yield put(A.linkToExchangeAccountLoading())

// check if wallet is already linked
const isExchangeAccountLinked = (yield select(
S.isExchangeAccountLinked
)).getOrFail()
const isExchangeAccountLinked = (yield select(S.isExchangeAccountLinked)).getOrFail()
if (isExchangeAccountLinked) {
throw new Error('Account has already been linked.')
}

// ensure email address is verified
const isEmailVerified = (yield select(
selectors.core.settings.getEmailVerified
)).getOrFail()
const isEmailVerified = (yield select(selectors.core.settings.getEmailVerified)).getOrFail()
if (!isEmailVerified) {
throw new Error('Email address is not verified.')
}

// check if wallet relink should be attempted
const isRelinkAttempt = (yield select(
S.isExchangeRelinkRequired
)).getOrFail()
const isRelinkAttempt = (yield select(S.isExchangeRelinkRequired)).getOrFail()

if (isRelinkAttempt) {
yield put(A.shareWalletAddressesWithExchange())
Expand All @@ -459,19 +444,16 @@ export default ({ api, coreSagas, networks }) => {
const isUserStateNone = (yield select(S.isUserStateNone)).getOrFail()
if (isUserStateNone) yield call(createUser)
// get exchange linkId, exchange domain and user email
const domains = (yield select(
selectors.core.walletOptions.getDomains
)).getOrFail()
const domains = (yield select(selectors.core.walletOptions.getDomains)).getOrFail()
const exchangeDomain = prop('exchange', domains)
const data = yield call(api.createLinkAccountId)
const exchangeLinkId = prop('linkId', data)
const email = (yield select(
selectors.core.settings.getEmail
)).getOrFail()
const email = (yield select(selectors.core.settings.getEmail)).getOrFail()
const accountDeeplinkUrl = `${exchangeDomain}/trade/link/${exchangeLinkId}?email=${encodeURIComponent(
email
)}&utm_source=web_wallet&utm_medium=referral&utm_campaign=${utmCampaign ||
'wallet_exchange_page'}`
)}&utm_source=web_wallet&utm_medium=referral&utm_campaign=${
utmCampaign || 'wallet_exchange_page'
}`
// share addresses
yield put(A.shareWalletAddressesWithExchange())
// simulate wait while allowing user to read modal
Expand All @@ -494,8 +476,6 @@ export default ({ api, coreSagas, networks }) => {
}
}



return {
clearSession,
createUser,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react'
import { FormattedMessage } from 'react-intl'
import { connect, ConnectedProps } from 'react-redux'
import { compose } from 'redux'
import styled from 'styled-components'

import { Icon, Modal, Text } from 'blockchain-info-components'
import { actions } from 'data'
import modalEnhancer from 'providers/ModalEnhancer'

const Header = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 10px;
margin: 30px 0 10px;
overflow: hidden;
text-align: center;
`
const Body = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 20px;
box-sizing: border-box;
text-align: center;
margin: 4px 0 14px;
& > :last-child {
margin: 15px 0;
}
`

class NabuUserConflictRedirect extends React.PureComponent<Props> {
render() {
const { errorMessage } = this.props
return (
<Modal size='small'>
<Header>
<Icon
name='alert-filled'
size='48px'
color='orange600'
style={{ marginBottom: '16px' }}
/>
<Text size='20px' weight={500}>
<FormattedMessage
defaultMessage='Your Trading Account is linked to another wallet'
id='modals.nabuuserconflict.title'
/>
</Text>
</Header>
<Body>
<Text size='14px' weight={500}>
<FormattedMessage
defaultMessage='Your Blockchain.com trading account is associated with another wallet. Please log into your wallet referenced below for account access.'
id='modals.nabuuserconflict.body'
/>
</Text>
<Text size='14px' weight={400}>
{errorMessage}
</Text>
</Body>
</Modal>
)
}
}

const mapDispatchToProps = (dispatch) => ({
closeModal: () => dispatch(actions.modals.closeModal())
})

const connector = connect(null, mapDispatchToProps)

type Props = ConnectedProps<typeof connector> & {
errorMessage: string
}

const enhance = compose<any>(
connect(null, mapDispatchToProps),
modalEnhancer('NABU_USER_CONFLICT_REDIRECT'),
connector
)

export default enhance(NabuUserConflictRedirect)
4 changes: 4 additions & 0 deletions packages/blockchain-wallet-v4-frontend/src/modals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const LinkToExchangeAccount = React.lazy(() => import('./Onboarding/LinkToExchan
const IdentityVerification = React.lazy(() => import('./Onboarding/KycVerification'))
const KycDocResubmit = React.lazy(() => import('./Onboarding/KycDocResubmit'))
const KycTierUpgrade = React.lazy(() => import('./Onboarding/KycTierUpgrade'))
const NabuUserConflictRedirect = React.lazy(() => import('./Onboarding/NabuUserConflictRedirect'))
const UpgradeForAirdrop = React.lazy(() => import('./Onboarding/UpgradeForAirdrop'))
const Welcome = React.lazy(() => import('./Onboarding/Welcome'))

Expand Down Expand Up @@ -200,6 +201,9 @@ const Modals = (props: Props) => {
{props.modals.find((modal) => modal.type === ModalName.MOBILE_NUMBER_VERIFY_MODAL) ? (
<MobileNumberVerify />
) : null}
{props.modals.find((modal) => modal.type === ModalName.NABU_USER_CONFLICT_REDIRECT) ? (
<NabuUserConflictRedirect />
) : null}
{props.modals.find((modal) => modal.type === ModalName.PAIRING_CODE_MODAL) ? (
<PairingCode />
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@ export const getData = (state: RootState): { bannerToShow: BannerType } => {
const isKycStateNone =
// @ts-ignore
selectors.modules.profile.getUserKYCState(state).getOrElse('') === 'NONE'

const isFirstLogin = selectors.auth.getFirstLogin(state)

const userDataR = selectors.modules.profile.getUserData(state)
const userData = userDataR.getOrElse({
tiers: { current: 0 }
} as UserDataType)

const { KYC_STATES } = model.profile
const isKycStatePending =
userData.kycState === KYC_STATES.PENDING || userData.kycState === KYC_STATES.UNDER_REVIEW
const sddEligibleTier = selectors.components.simpleBuy.getUserSddEligibleTier(state).getOrElse(1)

const limits = selectors.components.simpleBuy.getLimits(state).getOrElse({
Expand All @@ -56,7 +59,7 @@ export const getData = (state: RootState): { bannerToShow: BannerType } => {
const isTier3SDD = sddEligibleTier === 3

let bannerToShow: BannerType = null
if (showDocResubmitBanner) {
if (showDocResubmitBanner && !isKycStatePending) {
bannerToShow = 'resubmit'
} else if (isSimpleBuyOrderPending && !isTier3SDD) {
bannerToShow = 'sbOrder'
Expand Down

0 comments on commit 350c8d1

Please sign in to comment.