diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/index.js b/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/index.js
index 6e4893d2b02..228d041d850 100644
--- a/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/index.js
+++ b/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/index.js
@@ -30,12 +30,22 @@ class LinkContainer extends Component {
if (e.data.command === 'enablePlaid') this.setState({ enablePlaid: true })
if (e.data.command === 'disablePlaid') this.setState({ enablePlaid: false })
if (e.data.command === 'getBankAccounts' && e.data.msg) {
+ this.props.sfoxFrontendActions.sfoxLoading()
this.props.sfoxDataActions.getBankAccounts(e.data.msg)
this.setState({ enablePlaid: false, token: e.data.msg })
this.props.updateUI({ selectBank: true })
}
}
window.addEventListener('message', receiveMessage, false)
+
+ this.props.sfoxFrontendActions.sfoxLoading()
+ document.getElementById('plaid').onload = (e) => this.props.sfoxFrontendActions.sfoxSuccess()
+ }
+
+ componentDidUpdate () {
+ if (Remote.Success.is(this.props.bankAccounts) && Remote.Loading.is(this.props.linkStatus)) {
+ this.props.sfoxFrontendActions.sfoxSuccess()
+ }
}
onSetBankAccount (data) {
diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/template.js b/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/template.js
index 05ad6de6d28..324217cac1f 100644
--- a/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/template.js
+++ b/packages/blockchain-wallet-v4-frontend/src/modals/SfoxExchangeData/Link/template.js
@@ -29,6 +29,14 @@ const ButtonContainer = styled.div`
width: 75%;
margin-top: 20px;
`
+const BusyWrapper = styled.div`
+ display: ${props => !props.show ? 'flex' : 'none'};
+ flex-direction: column;
+`
+const LoaderWrapper = styled.div`
+ display: ${props => props.show ? 'flex' : 'none'};
+ justify-content: center;
+`
const OrText = styled.p`
color: rgba(151,151,151,0.5);
margin: 10px 0px 15px 0px;
@@ -141,19 +149,29 @@ const BankLink = (props) => {
{...props}
/>
} else if (bankAccounts) {
+ if (busy) {
+ return (
+
+ )
+ }
return
} else if (ui.microDeposits) {
return
} else {
return (
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
)
}
diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/index.js b/packages/blockchain-wallet-v4-frontend/src/modals/index.js
index 1cebe74ce5a..37394a393ef 100644
--- a/packages/blockchain-wallet-v4-frontend/src/modals/index.js
+++ b/packages/blockchain-wallet-v4-frontend/src/modals/index.js
@@ -6,6 +6,7 @@ import CoinifyDeleteBank from './CoinifyDeleteBank'
import CoinifyExchangeData from './CoinifyExchangeData'
import CoinifyTradeDetails from './CoinifyTradeDetails'
import ConfirmDisable2FA from './ConfirmDisable2FA'
+import DeleteAddressLabel from './DeleteAddressLabel'
import EditTxDescription from './EditTxDescription'
import ExchangeDetails from './ExchangeDetails'
import ImportBtcAddress from './ImportBtcAddress'
@@ -47,6 +48,7 @@ const Modals = props => (
+
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/CoinifyCheckout/Content/OrderReview.js b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/CoinifyCheckout/Content/OrderReview.js
index 785ed0e6347..c64f6aa9960 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/CoinifyCheckout/Content/OrderReview.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/CoinifyCheckout/Content/OrderReview.js
@@ -3,7 +3,7 @@ import styled from 'styled-components'
import { FormattedMessage } from 'react-intl'
import { Text, Link } from 'blockchain-info-components'
-import FaqRow from 'layouts/Wallet/TrayRight/Faq/FaqRow'
+import Helper from 'components/BuySell/FAQ'
import CountdownTimer from 'components/Form/CountdownTimer'
import { spacing } from 'services/StyleService'
import { reviewOrder, getRateFromQuote } from 'services/CoinifyService'
@@ -11,6 +11,7 @@ import { OrderDetailsTable, OrderDetailsRow } from 'components/BuySell/OrderDeta
import { BorderBox, Row } from 'components/BuySell/Signup'
import { StepTransition } from 'components/Utilities/Stepper'
import ReviewForm from './ReviewForm'
+import { update } from 'ramda'
const ExchangeRateWrapper = styled.div`
display: flex;
@@ -19,10 +20,6 @@ const ExchangeRateWrapper = styled.div`
justify-content: flex-end;
margin-top: 20px;
`
-const StyledFaqRow = styled(FaqRow)`
- padding: 20px 0px;
- border-bottom: 1px solid ${props => props.theme['gray-1']};
-`
const rateHelper = (quoteR) =>
quoteR.map(getRateFromQuote).getOrElse(`~`)
@@ -79,7 +76,31 @@ export const OrderDetails = ({ quoteR, onRefreshQuote, type, medium }) => (
)
export const OrderSubmit = (props) => {
- const { busy, clearTradeError, onSubmit, quoteR } = props
+ const { busy, clearTradeError, onSubmit, quoteR, type } = props
+
+ let helpers = [
+ {
+ question: ,
+ answer:
+ },
+ {
+ question: ,
+ answer:
+ },
+ {
+ question: ,
+ answer:
+ }
+ ]
+
+ let sellFaq = {
+ question: ,
+ answer:
+ }
+
+ const faqHelper = () => helpers.map((el, i) => )
+
+ if (type === 'sell') helpers = update(0, sellFaq, helpers)
return (
@@ -98,24 +119,7 @@ export const OrderSubmit = (props) => {
:
}
- }
- description={
-
-
-
-
-
- }
- />
- }
- description={}
- />
- }
- description={}
- />
+ { faqHelper() }
)
}
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/OrderCheckout.js b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/OrderCheckout.js
index 66fa3575ee1..e53dcd03297 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/OrderCheckout.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/OrderCheckout.js
@@ -3,12 +3,11 @@ import { Text, Icon, Button } from 'blockchain-info-components'
import { Wrapper as ExchangeCheckoutWrapper } from '../../ExchangeCheckout'
import { flex, spacing } from 'services/StyleService'
import { FormattedMessage } from 'react-intl'
-import { Remote } from 'blockchain-wallet-v4/src'
-import { StepTransition } from 'components/Utilities/Stepper'
import QuoteInput from './QuoteInput'
import FundingSource from 'components/BuySell/FundingSource'
import { MethodContainer } from 'components/BuySell/styled.js'
import * as Currency from 'blockchain-wallet-v4/src/exchange/currency'
+import { Remote } from 'blockchain-wallet-v4/src'
const quoteInputSpec = {
method: 'buy',
@@ -16,6 +15,11 @@ const quoteInputSpec = {
output: 'btc'
}
+const getCryptoMax = (q, max) => {
+ if (q.baseCurrency.toLowerCase() === 'btc') return max / ((1 / (Math.abs(q.baseAmount / 1e8))) * Math.abs(q.quoteAmount))
+ else return max / ((1 / (Math.abs(q.quoteAmount / 1e8))) * Math.abs(q.baseAmount))
+}
+
const OrderCheckout = ({ quoteR, account, onFetchQuote, reason, finishAccountSetup, limits, type, disableButton, enableButton, buttonStatus }) => {
const disableInputs = () => {
if (limits.max < limits.min) return 'max_below_min'
@@ -30,19 +34,9 @@ const OrderCheckout = ({ quoteR, account, onFetchQuote, reason, finishAccountSet
?
:
- const limitsHelper = (quoteR, limits) => {
- if (quoteR.error) return true
- return quoteR.map(q => {
- if (q.baseCurrency === 'USD') return +q.baseAmount > limits.max || +q.baseAmount < limits.min || +q.quoteAmount > limits.effectiveMax
- if (q.baseCurrency === 'BTC') return +q.quoteAmount > limits.max || +q.quoteAmount < limits.min || +q.baseAmount > limits.effectiveMax
- }).data
- }
-
const submitButtonHelper = () => (
reason.indexOf('has_remaining') > -1
- ?
-
-
+ ? null
:
You need to finish setting up your account before you can buy and sell.
@@ -64,17 +58,19 @@ const OrderCheckout = ({ quoteR, account, onFetchQuote, reason, finishAccountSet
Bitcoin
{'@ '}
- {quoteR
- .map(q => {
- if (q.baseCurrency.toLowerCase() === 'btc') return '$' + Currency.formatFiat((1 / (Math.abs(q.baseAmount / 1e8))) * Math.abs(q.quoteAmount))
- else return '$' + Currency.formatFiat((1 / (Math.abs(q.quoteAmount / 1e8))) * Math.abs(q.baseAmount))
- })
- .getOrElse(
-
+ {
+ Remote.Loading.is(quoteR)
+ ?
{'...'}
- )}
+ : quoteR
+ .map(q => {
+ if (q.baseCurrency.toLowerCase() === 'btc') return '$' + Currency.formatFiat((1 / (Math.abs(q.baseAmount / 1e8))) * Math.abs(q.quoteAmount))
+ else return '$' + Currency.formatFiat((1 / (Math.abs(q.quoteAmount / 1e8))) * Math.abs(q.baseAmount))
+ })
+ .getOrElse()
+ }
@@ -103,6 +99,8 @@ const OrderCheckout = ({ quoteR, account, onFetchQuote, reason, finishAccountSet
type={type}
disableButton={disableButton}
enableButton={enableButton}
+ reason={reason}
+ cryptoMax={quoteR.map(quote => getCryptoMax(quote, limits.max)).getOrElse()}
/>
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInput.js b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInput.js
index 0d771b587c4..4d365f2c4e2 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInput.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInput.js
@@ -4,7 +4,7 @@ import { toUpper, path } from 'ramda'
import FiatConvertor from './QuoteInputTemplate'
import { Remote } from 'blockchain-wallet-v4/src'
-const WrappedFiatConverter = ({ leftVal, leftUnit, rightVal, rightUnit, disabled, onChangeLeft, onChangeRight, limits }) => (
+const WrappedFiatConverter = ({ leftVal, leftUnit, rightVal, rightUnit, disabled, onChangeLeft, onChangeRight, limits, reason, quoteR, cryptoMax }) => (
{}}
meta={{}}
limits={limits}
+ quoteR={quoteR}
+ reason={reason}
+ cryptoMax={cryptoMax}
/>
)
@@ -65,7 +68,7 @@ class QuoteInput extends Component {
updateFields (quote) {
if (!this.state.userInput) return null
- let fiat = this.state.side === 'input' ? quote.baseAmount : quote.quoteAmount
+ let fiat = this.state.side === 'input' ? this.state.input : quote.quoteAmount
let crypto = this.state.side === 'output' ? quote.baseAmount / 1e8 : quote.quoteAmount / 1e8
this.setState({
input: fiat,
@@ -108,15 +111,14 @@ class QuoteInput extends Component {
fetchQuote = () => {
let quote = this.getQuoteValues()
+ if (quote.baseCurrency === 'BTC' && (quote.amt / 1e8) > this.props.cryptoMax) return null
+ if (quote.baseCurrency === 'USD' && (quote.amt / 100) > this.props.limits.max) return null
this.props.onFetchQuote(quote)
}
render () {
- let { spec, disabled, limits } = this.props
- let { input, output, fiatAmount, userInput } = this.state
-
- if (fiatAmount > limits.max || fiatAmount < limits.min) this.props.disableButton()
- else this.props.enableButton()
+ let { spec, disabled } = this.props
+ let { input, output, userInput } = this.state
return (
)
}
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInputTemplate.js b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInputTemplate.js
index e1c08ec4b5f..caa8a4586b8 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInputTemplate.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/BuySell/SfoxCheckout/Content/QuoteInputTemplate.js
@@ -1,12 +1,15 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
+import { StepTransition } from 'components/Utilities/Stepper'
+import { spacing } from 'services/StyleService'
+import { FormattedMessage } from 'react-intl'
+import { Remote } from 'blockchain-wallet-v4/src'
-import { Icon, TextInput, Text } from 'blockchain-info-components'
+import { Icon, TextInput, Text, Button } from 'blockchain-info-components'
const Wrapper = styled.div`
width: 100%;
- height: 40px;
display: flex;
position: relative;
flex-direction: column;
@@ -55,21 +58,32 @@ const Error = styled(Text)`
top: 42px;
right: 0;
`
+const ButtonWrapper = styled.div`
+ width: 100%;
+`
const getErrorState = (meta) => {
return !meta.touched ? 'initial' : (meta.invalid ? 'invalid' : 'valid')
}
-const getLimitsError = (val, limits, disabledReason, fiat) => {
+const getLimitsError = (val, limits, disabledReason, fiat, cryptoMax) => {
if (limits.max < limits.min) return `Your limit of $${limits.max} is below the minimum allowed amount.`
if (disabledReason === 'not_enough_funds') return `There are not enough funds to meet the sell minimum of $${limits.min.toLocaleString()}`
- if (val && val > limits.max) return `Enter an amount under your $${limits.max.toLocaleString()} limit`
+ if ((val && val > limits.max) || (fiat > cryptoMax)) return `Enter an amount under your $${limits.max.toLocaleString()} limit`
if (val && val < limits.min) return `Enter an amount above the $${limits.min.toLocaleString()} minimum`
if (!val || !fiat) return
if ((fiat * 1e8) > limits.effectiveMax) return `Enter an amount less than your balance minus the priority fee (${limits.effectiveMax / 1e8} BTC)`
}
+const limitsHelper = (quoteR, limits) => {
+ if (quoteR.error) return true
+ return quoteR.map(q => {
+ if (q.baseCurrency === 'USD') return +q.baseAmount > limits.max || +q.baseAmount < limits.min || +q.quoteAmount > limits.effectiveMax
+ if (q.baseCurrency === 'BTC') return +q.quoteAmount > limits.max || +q.quoteAmount < limits.min || +q.baseAmount > limits.effectiveMax
+ }).data
+}
+
const FiatConvertor = (props) => {
- const { value, fiat, disabled, handleBlur, handleCoinChange, handleFiatChange, handleFocus, handleErrorClick, meta, limits } = props
+ const { value, fiat, disabled, handleBlur, handleCoinChange, handleFiatChange, handleFocus, handleErrorClick, meta, limits, quoteR, reason, cryptoMax } = props
const { currency, unit } = props.data.data
const errorState = getErrorState(meta)
const disabledReason = disabled()
@@ -91,9 +105,18 @@ const FiatConvertor = (props) => {
{meta.touched && meta.error && {meta.error}}
{
limits &&
- { getLimitsError(value, limits, disabledReason, fiat) }
+ { getLimitsError(value, limits, disabledReason, fiat, cryptoMax) }
}
+ {
+ reason.indexOf('has_remaining') > -1
+ ?
+
+
+
+
+ : null
+ }
)
}
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Exchange/Shapeshift/StateRegistrationStep/template.js b/packages/blockchain-wallet-v4-frontend/src/scenes/Exchange/Shapeshift/StateRegistrationStep/template.js
index a292c4017bd..b954466ccd2 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/Exchange/Shapeshift/StateRegistrationStep/template.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Exchange/Shapeshift/StateRegistrationStep/template.js
@@ -31,10 +31,7 @@ const SubmitButton = styled(Button)`
`
const StateRegistrationStep = (props) => {
- const { handleSubmit, invalid, pristine, stateWhitelist } = props
- const onShapeshiftWhitelist = (state) => {
- return state.code && stateWhitelist.indexOf(state.code) >= 0 ? undefined : 'This service is not yet available in your state.'
- }
+ const { handleSubmit, invalid, pristine } = props
return (
@@ -55,7 +52,7 @@ const StateRegistrationStep = (props) => {
-
+
@@ -72,4 +69,11 @@ StateRegistrationStep.propTypes = {
stateWhitelist: PropTypes.array.isRequired
}
-export default reduxForm({ form: 'exchange' })(StateRegistrationStep)
+export default reduxForm({
+ form: 'exchange',
+ validate: (values, props) => {
+ return values.state && values.state.code && props.stateWhitelist.indexOf(values.state.code) >= 0
+ ? {}
+ : { state: }
+ }
+})(StateRegistrationStep)
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.js b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.js
index cd5e9189bdd..23612162483 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/index.js
@@ -11,7 +11,6 @@ class LoginContainer extends React.PureComponent {
super(props)
this.state = { useCode: true }
this.onSubmit = this.onSubmit.bind(this)
- this.handleCode = this.handleCode.bind(this)
this.handleMobile = this.handleMobile.bind(this)
this.handleSmsResend = this.handleSmsResend.bind(this)
}
@@ -19,14 +18,9 @@ class LoginContainer extends React.PureComponent {
this.props.formActions.destroy('login')
}
- handleCode (val) {
- this.setState({ useCode: val })
- }
-
onSubmit () {
- const { useCode } = this.state
const { guid, password, code } = this.props
- let auth = useCode ? code : undefined
+ let auth = code
// only uppercase if authType is not Yubikey
if (auth && this.props.authType !== 1) {
auth = auth.toUpperCase()
@@ -57,7 +51,6 @@ class LoginContainer extends React.PureComponent {
authType,
loginError: error,
onSubmit: this.onSubmit,
- handleCode: this.handleCode,
handleMobile: this.handleMobile,
handleSmsResend: this.handleSmsResend
}
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/template.js b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/template.js
index 79855720442..3adfccce0df 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/Login/template.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Login/template.js
@@ -70,8 +70,6 @@ const Login = (props) => {
const twoFactorError = loginError && loginError.toLowerCase().includes('authentication code')
const accountLocked = loginError && (loginError.toLowerCase().includes('this account has been locked') || loginError.toLowerCase().includes('account is locked'))
- const handlePasswordChange = () => { passwordError && props.handleCode(false) }
-
return (
@@ -143,7 +141,7 @@ const Login = (props) => {
-
+
{ passwordError && 0 ? 'relative' : 'absolute'}> }
{ accountLocked && 0 || passwordError ? 'relative' : 'absolute'}>{loginError} }
diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Reset2FA/FirstStep/template.js b/packages/blockchain-wallet-v4-frontend/src/scenes/Reset2FA/FirstStep/template.js
index 41b85b469cb..5267e090c8e 100644
--- a/packages/blockchain-wallet-v4-frontend/src/scenes/Reset2FA/FirstStep/template.js
+++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Reset2FA/FirstStep/template.js
@@ -10,7 +10,7 @@ import { Form, FormGroup, FormItem, FormLabel, TextBox } from 'components/Form'
const Wrapper = styled.div`
width: 100%;
- padding: 40px;
+ padding: 30px;
box-sizing: border-box;
background-color: ${props => props.theme['white']};
@@ -24,6 +24,9 @@ const Header = styled.div`
const FirstStepForm = styled(Form)`
margin-top: 15px;
`
+const InfoMsg = styled(Text)`
+ margin-top: 5px;
+`
const Footer = styled(FormGroup)`
display: flex;
flex-direction: row;
@@ -37,6 +40,10 @@ const GoBackLink = styled(LinkContainer)`
const FirstStep = (props) => {
const { submitting, invalid, handleSubmit } = props
+ const validNullableEmail = emailVal => {
+ return emailVal && emailVal.length ? validEmail(emailVal) : undefined
+ }
+
return (
@@ -44,7 +51,7 @@ const FirstStep = (props) => {
-
+
@@ -86,6 +93,17 @@ const FirstStep = (props) => {
+
+
+
+
+
+
+
+
+
+
+