diff --git a/packages/blockchain-wallet-v4-frontend/src/assets/locales/index.d.ts b/packages/blockchain-wallet-v4-frontend/src/assets/locales/index.d.ts index f867ef8be81..f345fee2930 100644 --- a/packages/blockchain-wallet-v4-frontend/src/assets/locales/index.d.ts +++ b/packages/blockchain-wallet-v4-frontend/src/assets/locales/index.d.ts @@ -288,6 +288,7 @@ type MessagesType = { 'components.txlistitem.watchonly': 'Non-Spendable' 'copy.address': 'Address' 'copy.amount': 'Amount' + 'copy.available': 'Available' 'copy.balance': 'Balance' 'copy.date': 'Date' 'copy.failed': 'Failed' diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/actions.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/actions.ts index bd8d5af3968..6465b9cc46b 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/actions.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/actions.ts @@ -8,6 +8,7 @@ import { SBAccountType, SBBalancesType, SBCardType, + SBOrderActionType, SBOrderType, SBPairType, SBPaymentMethodsType, @@ -373,9 +374,13 @@ export const initializeBillingAddress = () => ({ type: AT.INITIALIZE_BILLING_ADDRESS }) -export const initializeCheckout = (orderType: 'BUY' | 'SELL') => ({ +export const initializeCheckout = ( + orderType: SBOrderActionType, + amount?: string +) => ({ type: AT.INITIALIZE_CHECKOUT, - orderType + orderType, + amount }) export const pollSBBalances = () => ({ @@ -407,7 +412,6 @@ const getPayloadObjectForStep = (payload: StepActionsPayload) => { return { step: payload.step, cryptoCurrency: payload.cryptoCurrency, - defaultMethod: payload.defaultMethod, fiatCurrency: payload.fiatCurrency, order: payload.order, pair: payload.pair @@ -416,7 +420,6 @@ const getPayloadObjectForStep = (payload: StepActionsPayload) => { return { step: payload.step, cryptoCurrency: payload.cryptoCurrency, - defaultMethod: payload.defaultMethod, fiatCurrency: payload.fiatCurrency, method: payload.method, pair: payload.pair @@ -430,7 +433,8 @@ const getPayloadObjectForStep = (payload: StepActionsPayload) => { case 'TRANSFER_DETAILS': return { step: payload.step, - fiatCurrency: payload.fiatCurrency + fiatCurrency: payload.fiatCurrency, + displayBack: payload.displayBack } case 'CHECKOUT_CONFIRM': case 'ORDER_SUMMARY': diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/model.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/model.ts index 21e3c2a2c11..c2688beead7 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/model.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/model.ts @@ -4,6 +4,7 @@ import { FiatType, FiatTypeEnum, SBCardType, + SBOrderActionType, SBOrderType, SBPairsType, SBQuoteType @@ -30,7 +31,7 @@ export const splitPair = ( return pair.split('-') as [FiatType | CoinType, '-', FiatType | CoinType] } -export const getOrderType = (pair: SBPairsType): 'BUY' | 'SELL' => { +export const getOrderType = (pair: SBPairsType): SBOrderActionType => { return splitPair(pair)[0] in FiatTypeEnum ? 'SELL' : 'BUY' } diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/reducers.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/reducers.ts index 3b9c559b023..0a1a68042ae 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/reducers.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/reducers.ts @@ -8,8 +8,8 @@ const INITIAL_STATE: SimpleBuyState = { card: Remote.NotAsked, cardId: undefined, cards: Remote.NotAsked, + displayBack: false, cryptoCurrency: undefined, - defaultMethod: undefined, everypay3DS: Remote.NotAsked, fiatCurrency: undefined, fiatEligible: Remote.NotAsked, @@ -67,7 +67,6 @@ export function simpleBuyReducer ( ...state, account: Remote.NotAsked, cardId: undefined, - defaultMethod: undefined, order: undefined, pairs: Remote.NotAsked, quote: Remote.NotAsked, @@ -241,7 +240,6 @@ export function simpleBuyReducer ( return { ...state, cryptoCurrency: action.payload.cryptoCurrency, - defaultMethod: action.payload.defaultMethod, fiatCurrency: action.payload.fiatCurrency, step: action.payload.step, pair: action.payload.pair, @@ -253,14 +251,12 @@ export function simpleBuyReducer ( ...state, cryptoCurrency: action.payload.cryptoCurrency, fiatCurrency: action.payload.fiatCurrency, - step: action.payload.step, - order: undefined + step: action.payload.step } case 'PAYMENT_METHODS': return { ...state, cryptoCurrency: action.payload.cryptoCurrency, - defaultMethod: action.payload.defaultMethod, fiatCurrency: action.payload.fiatCurrency, step: action.payload.step, order: action.payload.order @@ -278,7 +274,8 @@ export function simpleBuyReducer ( return { ...state, step: action.payload.step, - fiatCurrency: action.payload.fiatCurrency + fiatCurrency: action.payload.fiatCurrency, + displayBack: action.payload.displayBack } default: { return { diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/sagas.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/sagas.ts index b7e92c0d92c..bc8929db855 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/sagas.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/sagas.ts @@ -30,6 +30,7 @@ import { NO_PAIR_SELECTED } from './model' import { errorHandler } from 'blockchain-wallet-v4/src/utils' +import { Remote } from 'blockchain-wallet-v4/src' import { SBAddCardErrorType, SBAddCardFormValuesType, @@ -458,7 +459,12 @@ export default ({ ) } yield call(createUser) - yield put(A.fetchSBPaymentMethodsLoading()) + + // Only show Loading if NotAsked + const sbMethodsR = S.getSBPaymentMethods(yield select()) + if (Remote.NotAsked.is(sbMethodsR)) + yield put(A.fetchSBPaymentMethodsLoading()) + const methods = yield call( api.getSBPaymentMethods, currency, @@ -535,7 +541,8 @@ export default ({ } const initializeCheckout = function * ({ - orderType + orderType, + amount }: ReturnType) { try { yield call(createUser) @@ -548,7 +555,8 @@ export default ({ yield put( actions.form.initialize('simpleBuyCheckout', { - orderType + orderType, + amount } as SBCheckoutFormValuesType) ) } catch (e) { diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/selectors.ts index 5fffb78b319..f1d452a9efd 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/selectors.ts @@ -1,3 +1,5 @@ +import { ExtractSuccess, SBPaymentMethodType } from 'core/types' +import { head, lift } from 'ramda' import { RootState } from 'data/rootReducer' export const getEverypay3DSDetails = (state: RootState) => @@ -9,11 +11,56 @@ export const getSBAccount = (state: RootState) => export const getCryptoCurrency = (state: RootState) => state.components.simpleBuy.cryptoCurrency +export const getDisplayBack = (state: RootState) => + state.components.simpleBuy.displayBack + export const getFiatCurrency = (state: RootState) => state.components.simpleBuy.fiatCurrency || state.preferences.sbFiatCurrency -export const getDefaultMethod = (state: RootState) => - state.components.simpleBuy.defaultMethod +export const getDefaultPaymentMethod = (state: RootState) => { + const ordersR = getSBOrders(state) + const sbCardsR = getSBCards(state) + const sbMethodsR = getSBPaymentMethods(state) + + const transform = ( + orders: ExtractSuccess, + sbCards: ExtractSuccess, + sbMethods: ExtractSuccess + ): SBPaymentMethodType | undefined => { + const lastOrder = head(orders) + if (!lastOrder) return undefined + + const methodsOfType = sbMethods.methods.filter( + method => method.type === lastOrder.paymentType + ) + + switch (lastOrder.paymentType) { + case 'PAYMENT_CARD': + const method = head(methodsOfType) + if (!method) return + const sbCard = sbCards.find( + value => value.id === lastOrder.paymentMethodId + ) + const card = sbCard?.card || undefined + + return { + ...method, + type: 'USER_CARD', + card + } + case 'FUNDS': + return methodsOfType.find( + method => method.currency === lastOrder.inputCurrency + ) + case 'BANK_ACCOUNT': + case 'USER_CARD': + case undefined: + return undefined + } + } + + return lift(transform)(ordersR, sbCardsR, sbMethodsR) +} export const getSBBalances = (state: RootState) => state.components.simpleBuy.balances diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/types.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/types.ts index 729e8d6579e..0f4cb2eaafc 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/types.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/simpleBuy/types.ts @@ -9,6 +9,7 @@ import { SBAccountType, SBBalancesType, SBCardType, + SBOrderActionType, SBOrderType, SBPairType, SBPaymentMethodsType, @@ -34,7 +35,7 @@ export type SBAddCardErrorType = export type SBBillingAddressFormValuesType = NabuAddressType export type SBCheckoutFormValuesType = { amount: string - orderType: 'BUY' | 'SELL' + orderType: SBOrderActionType } export type SBCurrencySelectFormType = { search: string @@ -70,7 +71,7 @@ export type SimpleBuyState = { cardId: undefined | string cards: RemoteDataType> cryptoCurrency: undefined | CoinType - defaultMethod: undefined | SBPaymentMethodType + displayBack: boolean everypay3DS: RemoteDataType fiatCurrency: undefined | FiatType fiatEligible: RemoteDataType @@ -290,7 +291,6 @@ export type StepActionsPayload = } | { cryptoCurrency?: CoinType - defaultMethod?: SBPaymentMethodType fiatCurrency: FiatType method?: SBPaymentMethodType order?: SBOrderType @@ -303,12 +303,12 @@ export type StepActionsPayload = step: 'CRYPTO_SELECTION' } | { + displayBack: boolean fiatCurrency: FiatType step: 'TRANSFER_DETAILS' } | { cryptoCurrency: CoinType - defaultMethod?: SBPaymentMethodType fiatCurrency: FiatType order?: SBOrderType pair: SBPairType diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/index.tsx index 8d5cac09321..a44e8328348 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/index.tsx @@ -3,7 +3,7 @@ import { bindActionCreators, Dispatch } from 'redux' import { connect, ConnectedProps } from 'react-redux' import { getData } from './selectors' import { RootState } from 'data/rootReducer' -import { SBPairType, SupportedWalletCurrenciesType } from 'core/types' +import { SBPairType } from 'core/types' import React, { PureComponent } from 'react' import Success from './template.success' @@ -29,8 +29,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ const connector = connect(mapStateToProps, mapDispatchToProps) export type OwnProps = { - onClick: (string) => void - supportedCoins: SupportedWalletCurrenciesType + onClick?: (string) => void value: SBPairType } export type SuccessStateType = ReturnType['data'] diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/selectors.ts index bab404c5870..58bd0a6b0cf 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/selectors.ts @@ -10,9 +10,16 @@ export const getData = (state: RootState, ownProps: OwnProps) => { const coin = getCoinFromPair(ownProps.value.pair) const ratesR = selectors.core.data.misc.getRatesSelector(coin, state) const fiatCurrency = selectors.components.simpleBuy.getFiatCurrency(state) + const supportedCoinsR = selectors.core.walletOptions.getSupportedCoins(state) - return lift((rates: ExtractSuccess) => ({ - fiatCurrency, - rates - }))(ratesR) + return lift( + ( + rates: ExtractSuccess, + supportedCoins: ExtractSuccess + ) => ({ + fiatCurrency, + rates, + supportedCoins + }) + )(ratesR, supportedCoinsR) } diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/template.success.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/template.success.tsx index a468d300d52..f22bb832bd8 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/template.success.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/CryptoItem/template.success.tsx @@ -30,13 +30,13 @@ const DisplayContainer = styled.div<{ background-color: ${props => props.theme.grey100}; } ` -const Display = styled.div` +const Display = styled.div<{ canClick: boolean }>` position: relative; display: flex; flex-direction: column; margin-left: 12px; width: 100%; - cursor: pointer; + cursor: ${props => (props.canClick ? 'pointer' : 'initial')}; font-size: 16px; font-weight: 500; color: ${props => props.theme.grey800}; @@ -65,7 +65,7 @@ const Success: React.FC = props => { onClick={props.onClick} > - + {displayName} {fiatToString({ @@ -75,7 +75,9 @@ const Success: React.FC = props => { - + {props.onClick && ( + + )} ) } diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/index.tsx index 119cc0a8057..e952c18e4a2 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/CryptoSelector/index.tsx @@ -72,7 +72,6 @@ const CryptoSelector: React.FC & handleSubmit(value as SBPairType)} /> ))} diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/selectors.ts index 0795aea37ef..07a68693ff5 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/CryptoSelection/selectors.ts @@ -1,24 +1,21 @@ -import { ExtractSuccess, SupportedWalletCurrenciesType } from 'core/types' +import { ExtractSuccess } from 'core/types' import { lift } from 'ramda' import { selectors } from 'data' export const getData = state => { const eligibilityR = selectors.components.simpleBuy.getSBFiatEligible(state) const pairsR = selectors.components.simpleBuy.getSBPairs(state) - const supportedCoinsR = selectors.core.walletOptions.getSupportedCoins(state) const userDataR = selectors.modules.profile.getUserData(state) return lift( ( eligibility: ExtractSuccess, pairs: ExtractSuccess, - supportedCoins: SupportedWalletCurrenciesType, userData: ExtractSuccess ) => ({ eligibility, pairs, - supportedCoins, userData }) - )(eligibilityR, pairsR, supportedCoinsR, userDataR) + )(eligibilityR, pairsR, userDataR) } diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/Payment/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/Payment/index.tsx index 42f7d770943..bb4f79935d1 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/Payment/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/Payment/index.tsx @@ -5,12 +5,12 @@ import { import { convertBaseToStandard } from 'data/components/exchange/services' import { DisplayIcon } from 'components/SimpleBuy' import { fiatToString } from 'core/exchange/currency' -import { FiatType, SBPaymentMethodType } from 'core/types' import { FormattedMessage } from 'react-intl' import { IcoMoonType } from 'blockchain-info-components/src/Icons/Icomoon' import { Icon, Text } from 'blockchain-info-components' -import { Props } from '..' -import { Title } from 'components/Flyout' +import { Props } from '../template.success' +import { SBBalancesType, SBPaymentMethodType, WalletFiatType } from 'core/types' +import { Title, Value } from 'components/Flyout' import React, { ReactElement } from 'react' import styled, { css } from 'styled-components' @@ -53,21 +53,10 @@ const PaymentArrowContainer = styled.div` justify-content: center; ` const DisplayTitle = styled(Title)` - align-items: left; - font-weight: 600; - display: flex; - flex-direction: column; - line-height: 24px; - color: ${props => props.theme.textBlack}; - width: 100%; + margin-top: 4px; ` -const DisplaySubTitle = styled(Title)` - align-items: left; - font-weight: 500; - font-size: 12px; - line-height: 24px; - color: ${props => props.theme.grey600}; - width: 100%; +const DisplayValue = styled(Value)` + margin-top: 0px; ` const DisplayPaymentIcon = styled(DisplayIcon)` @@ -92,31 +81,35 @@ const renderCardText = (value: SBPaymentMethodType): string => { const renderCard = (value: SBPaymentMethodType) => ( <> - {renderCardText(value)} - + {renderCardText(value)} + - + ) -const renderFund = (value: SBPaymentMethodType) => ( +const renderFund = (value: SBPaymentMethodType, sbBalances: SBBalancesType) => ( <> - {value.currency} - + {value.currency} + {fiatToString({ - value: convertBaseToStandard('FIAT', value.limits.max), - unit: String(value.currency) as FiatType - })} - + value: convertBaseToStandard( + 'FIAT', + sbBalances[value.currency as WalletFiatType]?.available + ), + unit: String(value.currency) as WalletFiatType + })}{' '} + + ) @@ -158,7 +151,10 @@ const getIcon = (value: SBPaymentMethodType | undefined): ReactElement => { } } -const getText = (value: SBPaymentMethodType | undefined): ReactElement => { +const getText = ( + value: SBPaymentMethodType | undefined, + sbBalances: SBBalancesType +): ReactElement => { if (!value) { return ( { ) } - return value.type === 'USER_CARD' ? renderCard(value) : renderFund(value) + return value.type === 'USER_CARD' + ? renderCard(value) + : renderFund(value, sbBalances) } const Payment: React.FC = props => ( props.simpleBuyActions.setStep({ step: 'PAYMENT_METHODS', @@ -186,7 +185,9 @@ const Payment: React.FC = props => ( {getIcon(props.method)} - {getText(props.method)} + + {getText(props.method, props.sbBalances)} + diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/index.tsx index a5bfb63372a..3c917e33af1 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/index.tsx @@ -7,8 +7,7 @@ import { } from '../index' import { getData } from './selectors' import { RootState } from 'data/rootReducer' -import { SBPaymentTypes } from 'core/types' -import { UserDataType } from 'data/types' +import { SBCheckoutFormValuesType, UserDataType } from 'data/types' import Failure from '../template.failure' import Loading from './template.loading' import React, { PureComponent } from 'react' @@ -16,27 +15,28 @@ import Success from './template.success' class Checkout extends PureComponent { componentDidMount () { - this.props.simpleBuyActions.initializeCheckout('BUY') + const amount = this.props.formValues?.amount + this.props.simpleBuyActions.initializeCheckout('BUY', amount) } handleSubmit = () => { // if the user is < tier 2 go to kyc but save order info // if the user is tier 2 try to submit order, let BE fail - const { formValues, userData } = this.props.data.getOrElse({ + const { formValues } = this.props + const { userData } = this.props.data.getOrElse({ userData: { tiers: { current: 0, next: 0, selected: 0 } } as UserDataType } as SuccessStateType) + const method = this.props.method || this.props.defaultMethod + if (userData.tiers.current < 2) { this.props.identityVerificationActions.verifyIdentity( 2, false, 'SBEnterAmountCheckout' ) - this.props.simpleBuyActions.createSBOrder( - undefined, - this.props.method?.type as SBPaymentTypes - ) - } else if (!this.props.method) { + this.props.simpleBuyActions.createSBOrder(undefined, method?.type) + } else if (!method) { const fiatCurrency = this.props.fiatCurrency || 'USD' this.props.simpleBuyActions.setStep({ step: 'PAYMENT_METHODS', @@ -45,22 +45,20 @@ class Checkout extends PureComponent { cryptoCurrency: this.props.cryptoCurrency, order: this.props.order }) - } else if (formValues && this.props.method) { - switch (this.props.method.type) { + } else if (formValues && method) { + switch (method.type) { case 'PAYMENT_CARD': this.props.simpleBuyActions.setStep({ step: 'ADD_CARD' }) break case 'USER_CARD': - this.props.simpleBuyActions.createSBOrder(this.props.method.id) + this.props.simpleBuyActions.createSBOrder(method.id) break + case 'FUNDS': case 'BANK_ACCOUNT': - this.props.simpleBuyActions.createSBOrder() + this.props.simpleBuyActions.createSBOrder(undefined, method.type) break - case 'FUNDS': - // eslint-disable-next-line - console.log('Payment method type not supported.') } } } @@ -86,9 +84,12 @@ class Checkout extends PureComponent { const mapStateToProps = (state: RootState) => ({ data: getData(state), - fiatCurrency: selectors.components.simpleBuy.getFiatCurrency(state), cryptoCurrency: - selectors.components.simpleBuy.getCryptoCurrency(state) || 'BTC' + selectors.components.simpleBuy.getCryptoCurrency(state) || 'BTC', + fiatCurrency: selectors.components.simpleBuy.getFiatCurrency(state), + formValues: selectors.form.getFormValues('simpleBuyCheckout')(state) as + | SBCheckoutFormValuesType + | undefined }) const mapDispatchToProps = dispatch => ({ diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/selectors.ts index b9ec8245f4c..a7ab8c3eb5b 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/selectors.ts @@ -1,36 +1,31 @@ -import { ExtractSuccess, SupportedWalletCurrenciesType } from 'core/types' +import { ExtractSuccess } from 'core/types' import { lift } from 'ramda' import { RootState } from 'data/rootReducer' -import { SBCheckoutFormValuesType } from 'data/types' import { selectors } from 'data' export const getData = (state: RootState) => { const formErrors = selectors.form.getFormSyncErrors('simpleBuyCheckout')( state ) - const formValues = selectors.form.getFormValues('simpleBuyCheckout')( - state - ) as SBCheckoutFormValuesType const invitationsR = selectors.core.settings.getInvitations(state) const suggestedAmountsR = selectors.components.simpleBuy.getSBSuggestedAmounts( state ) - const supportedCoinsR = selectors.core.walletOptions.getSupportedCoins(state) + const sbBalancesR = selectors.components.simpleBuy.getSBBalances(state) const userDataR = selectors.modules.profile.getUserData(state) return lift( ( invitations: ExtractSuccess, + sbBalances: ExtractSuccess, suggestedAmounts: ExtractSuccess, - supportedCoins: SupportedWalletCurrenciesType, userData: ExtractSuccess ) => ({ formErrors, - formValues, invitations, + sbBalances, suggestedAmounts, - supportedCoins, userData }) - )(invitationsR, suggestedAmountsR, supportedCoinsR, userDataR) + )(invitationsR, sbBalancesR, suggestedAmountsR, userDataR) } diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/template.success.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/template.success.tsx index a00e560f28e..c2ef8a46dbb 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/template.success.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/template.success.tsx @@ -18,6 +18,7 @@ import { Icon, Text } from 'blockchain-info-components' import { Props as OwnProps, SuccessStateType } from '.' import { SBCheckoutFormValuesType } from 'data/types' import ActionButton from './ActionButton' +import CryptoItem from '../../CryptoSelection/CryptoSelector/CryptoItem' import Currencies from 'blockchain-wallet-v4/src/exchange/currencies' import Failure from '../template.failure' import Payment from './Payment' @@ -28,13 +29,16 @@ const CustomForm = styled(Form)` height: 100%; display: flex; flex-direction: column; - justify-content: space-between; ` const TopText = styled(Text)` display: flex; align-items: center; justify-content: space-between; - margin-bottom: 24px; + margin-bottom: 16px; +` +const LeftTopCol = styled.div` + display: flex; + align-items: center; ` // Hide the default field error for NumberBox > div > div:last-child const AmountFieldContainer = styled.div` @@ -92,8 +96,6 @@ const ErrorText = styled(Text)` margin-bottom: 16px; ` -export type Props = OwnProps & SuccessStateType - const normalizeAmount = ( value, prevValue, @@ -104,7 +106,8 @@ const normalizeAmount = ( } const Success: React.FC & Props> = props => { - const { fiatCurrency } = props + const { fiatCurrency, method: selectedMethod, defaultMethod } = props + const method = selectedMethod || defaultMethod if (!props.formValues) return null if (!fiatCurrency) @@ -126,19 +129,36 @@ const Success: React.FC & Props> = props => { const prop = amtError === 'ABOVE_MAX' ? 'max' : 'min' const value = convertStandardToBase( 'FIAT', - getMaxMin(props.pair, prop, props.formValues, props.method) + getMaxMin(props.pair, prop, props.sbBalances, props.formValues, method) ) props.simpleBuyActions.handleSBSuggestedAmountClick(value) } return ( - + - + + + props.simpleBuyActions.setStep({ + step: 'CRYPTO_SELECTION', + fiatCurrency: props.fiatCurrency || 'USD' + }) + } + /> + + & Props> = props => { onClick={() => props.handleClose()} /> + + + {Currencies[fiatCurrency].units[fiatCurrency].symbol} @@ -180,10 +203,10 @@ const Success: React.FC & Props> = props => { value: getMaxMin( props.pair, 'max', + props.sbBalances, props.formValues, - props.method - ), - digits: 0 + method + ) }), orderType: props.formValues.orderType === 'BUY' ? 'Buy' : 'Sell' @@ -199,10 +222,10 @@ const Success: React.FC & Props> = props => { value: getMaxMin( props.pair, 'min', + props.sbBalances, props.formValues, - props.method - ), - digits: 0 + method + ) }), orderType: props.formValues.orderType === 'BUY' ? 'Buy' : 'Sell' @@ -264,7 +287,7 @@ const Success: React.FC & Props> = props => { )} - + {props.error && ( @@ -282,6 +305,8 @@ const Success: React.FC & Props> = props => { ) } +export type Props = OwnProps & SuccessStateType + export default reduxForm<{}, Props>({ form: 'simpleBuyCheckout', destroyOnUnmount: false diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/validation.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/validation.tsx index ab7a2f26f0a..09d7b301248 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/validation.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/Checkout/validation.tsx @@ -1,12 +1,13 @@ import { convertBaseToStandard } from 'data/components/exchange/services' import { Props } from './template.success' +import { SBBalancesType, SBPairType, SBPaymentMethodType } from 'core/types' import { SBCheckoutFormValuesType } from 'data/types' -import { SBPairType, SBPaymentMethodType } from 'core/types' import BigNumber from 'bignumber.js' export const getMaxMin = ( pair: SBPairType, - minOrMax?: 'min' | 'max', + minOrMax: 'min' | 'max', + sbBalances: SBBalancesType, allValues?: SBCheckoutFormValuesType, method?: SBPaymentMethodType ) => { @@ -17,7 +18,10 @@ export const getMaxMin = ( if (!method) return defaultMax if (!pair) return defaultMax - const max = BigNumber.minimum(method.limits.max, pair.buyMax).toString() + let max = BigNumber.minimum(method.limits.max, pair.buyMax).toString() + + if (method.type === 'FUNDS' && sbBalances) + max = sbBalances[method.currency].available return convertBaseToStandard('FIAT', max) case 'min': @@ -39,10 +43,12 @@ export const maximumAmount = ( ) => { if (!value) return true - const { pair, method } = restProps + const { pair, method: selectedMethod, defaultMethod, sbBalances } = restProps + const method = selectedMethod || defaultMethod if (!method) return true - return Number(value) > Number(getMaxMin(pair, 'max', allValues, method)) + return Number(value) > + Number(getMaxMin(pair, 'max', sbBalances, allValues, method)) ? 'ABOVE_MAX' : false } @@ -54,10 +60,12 @@ export const minimumAmount = ( ) => { if (!value) return true - const { pair, method } = restProps + const { pair, method: selectedMethod, defaultMethod, sbBalances } = restProps + const method = selectedMethod || defaultMethod if (!method) return true - return Number(value) < Number(getMaxMin(pair, 'min', allValues, method)) + return Number(value) < + Number(getMaxMin(pair, 'min', sbBalances, allValues, method)) ? 'BELOW_MIN' : false } diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/index.tsx index 15ab18089ba..961ec70a92d 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/index.tsx @@ -2,13 +2,11 @@ import { actions, selectors } from 'data' import { bindActionCreators, Dispatch } from 'redux' import { connect, ConnectedProps } from 'react-redux' import { - FiatEligibleType, + ExtractSuccess, FiatType, RemoteDataType, - SBCardType, SBOrderType, SBPairType, - SBPaymentMethodsType, SBPaymentMethodType } from 'core/types' import { getData } from './selectors' @@ -20,10 +18,10 @@ import Success from './template.success' class EnterAmount extends PureComponent { componentDidMount () { - if (this.props.fiatCurrency) { + if (this.props.fiatCurrency && !this.props.method) { this.props.simpleBuyActions.fetchSBPaymentMethods(this.props.fiatCurrency) - this.props.simpleBuyActions.fetchSBCards() this.props.simpleBuyActions.fetchSBOrders() + this.props.simpleBuyActions.fetchSBCards() } } @@ -56,11 +54,7 @@ export type OwnProps = { order?: SBOrderType pair: SBPairType } -export type SuccessStateType = { - cards: Array - eligibility: FiatEligibleType - paymentMethods: SBPaymentMethodsType -} +export type SuccessStateType = ExtractSuccess> export type LinkStatePropsType = { data: RemoteDataType fiatCurrency: undefined | FiatType diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/selectors.ts index 616b2cc5709..a215c5490ce 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/EnterAmount/selectors.ts @@ -1,16 +1,25 @@ +import { ExtractSuccess } from 'core/types' import { lift } from 'ramda' import { selectors } from 'data' export const getData = state => { - const cardsR = selectors.components.simpleBuy.getSBCards(state) + const defaultMethodR = selectors.components.simpleBuy.getDefaultPaymentMethod( + state + ) const eligibilityR = selectors.components.simpleBuy.getSBFiatEligible(state) const paymentMethodsR = selectors.components.simpleBuy.getSBPaymentMethods( state ) - return lift((cards, eligibility, paymentMethods) => ({ - cards, - eligibility, - paymentMethods - }))(cardsR, eligibilityR, paymentMethodsR) + return lift( + ( + defaultMethod: ExtractSuccess, + eligibility: ExtractSuccess, + paymentMethods: ExtractSuccess + ) => ({ + defaultMethod, + eligibility, + paymentMethods + }) + )(defaultMethodR, eligibilityR, paymentMethodsR) } diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/PaymentMethods/Payments/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/PaymentMethods/Payments/index.tsx index ba92f90d6d2..66880af4ddb 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/PaymentMethods/Payments/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/PaymentMethods/Payments/index.tsx @@ -227,7 +227,8 @@ class Payments extends PureComponent & Props> { onClick={() => this.props.simpleBuyActions.setStep({ step: 'TRANSFER_DETAILS', - fiatCurrency + fiatCurrency, + displayBack: true }) } /> diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/index.tsx index 220fef5f819..1e75ed58e56 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/index.tsx @@ -1,7 +1,14 @@ import { actions } from 'data' import { bindActionCreators, Dispatch } from 'redux' +import { + CoinType, + FiatType, + RemoteDataType, + SBAccountType, + SBOrderType, + SBPairType +} from 'core/types' import { connect, ConnectedProps } from 'react-redux' -import { FiatType, RemoteDataType, SBAccountType } from 'core/types' import { getData } from './selectors' import { RootState } from 'data/rootReducer' import { UserDataType } from 'data/types' @@ -39,8 +46,12 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ const connector = connect(mapStateToProps, mapDispatchToProps) export type OwnProps = { + cryptoCurrency?: CoinType + displayBack?: boolean fiatCurrency: FiatType handleClose: () => void + order?: SBOrderType + pair: SBPairType } export type SuccessStateType = { account: SBAccountType diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/template.success.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/template.success.tsx index c6b512f40c6..3201e5216ed 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/template.success.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/TransferDetails/template.success.tsx @@ -68,10 +68,49 @@ const Copy = styled.div` display: flex; ` +const BackIcon = styled(Icon)` + position: absolute; + left: 40px; + top: 20px; +` + +const CloseIcon = styled(Icon)` + position: absolute; + right: 28px; + top: 28px; +` + const Success: React.FC = props => { return (
+ {props.displayBack && ( + + props.simpleBuyActions.setStep({ + step: 'PAYMENT_METHODS', + fiatCurrency: props.fiatCurrency || 'USD', + pair: props.pair, + cryptoCurrency: props.cryptoCurrency || 'BTC', + order: props.order + }) + } + /> + )} + + props.handleClose()} + /> = props => { currency: Currencies[props.fiatCurrency].displayName }} /> - props.handleClose()} - /> ({ method: selectors.components.simpleBuy.getSBPaymentMethod(state), order: selectors.components.simpleBuy.getSBOrder(state), cryptoCurrency: selectors.components.simpleBuy.getCryptoCurrency(state), - fiatCurrency: selectors.components.simpleBuy.getFiatCurrency(state) + fiatCurrency: selectors.components.simpleBuy.getFiatCurrency(state), + displayBack: selectors.components.simpleBuy.getDisplayBack(state) }) const mapDispatchToProps = (dispatch: Dispatch): LinkDispatchPropsType => ({ @@ -167,7 +168,9 @@ type LinkStatePropsType = | 'CC_BILLING_ADDRESS' } | { + displayBack?: boolean fiatCurrency: FiatType + pair: SBPairType step: 'TRANSFER_DETAILS' } | { diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Settings/General/LinkedCards/template.success.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Settings/General/LinkedCards/template.success.tsx index cdeaa30a4c4..dccb0fcd60a 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Settings/General/LinkedCards/template.success.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Settings/General/LinkedCards/template.success.tsx @@ -5,7 +5,7 @@ import { } from 'components/Form/CreditCardBox/model' import { convertBaseToStandard } from 'data/components/exchange/services' import { fiatToString } from 'core/exchange/currency' -import { FiatType, SBPaymentMethodType } from 'core/types' +import { FiatType } from 'core/types' import { FormattedMessage } from 'react-intl' import { InjectedFormProps, reduxForm } from 'redux-form' import { Props as OwnProps, SuccessStateType } from '.' @@ -94,13 +94,7 @@ const Success: React.FC { if (props.submitting) return - props.handleCreditCardClick({ - ...card, - type: 'USER_CARD', - limits: ccPaymentMethod - ? ccPaymentMethod.limits - : { min: '500', max: '50000' } - }) + props.handleCreditCardClick() }} > @@ -170,7 +164,7 @@ const Success: React.FC void + handleCreditCardClick: () => void } export default reduxForm<{}, Props>({ form: 'linkedCards' })(Success) diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/index.tsx index 8d6f717759c..e309d94cb74 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/index.tsx @@ -1,16 +1,17 @@ import { actions, model } from 'data' import { bindActionCreators, compose, Dispatch } from 'redux' +import { Button, Icon, Text } from 'blockchain-info-components' import { CoinType, CoinTypeEnum, FiatType, FiatTypeEnum, - SupportedCoinType + SupportedCoinType, + WalletFiatType } from 'core/types' import { connect, ConnectedProps } from 'react-redux' import { getData } from './selectors' import { getHeaderExplainer } from './template.headerexplainer' -import { Icon, Text } from 'blockchain-info-components' import { path, toLower } from 'ramda' import { reduxForm } from 'redux-form' import { SceneWrapper } from 'components/Layout' @@ -28,6 +29,11 @@ import TransactionList from './TransactionList' import WalletBalanceDropdown from './WalletBalanceDropdown' const PageTitle = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +` +const CoinTitle = styled.div` display: flex; flex-direction: row; width: 100%; @@ -37,6 +43,7 @@ const PageTitle = styled.div` margin-right: 14px; } ` +const TitleActionContainer = styled.div`` const Header = styled.div` width: 100%; ` @@ -119,10 +126,32 @@ class TransactionsContainer extends React.PureComponent {
- - - {displayName} - + + + + {displayName} + + + + {coin in FiatTypeEnum && ( + + )} + {getHeaderExplainer(coinModel)} @@ -194,7 +223,11 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps) => { dispatch(actions.components.fiatTransactions.loadMore(coin)), initTxs: () => dispatch(actions.components.fiatTransactions.initialized(coin)), - miscActions: bindActionCreators(actions.core.data.misc, dispatch) + miscActions: bindActionCreators(actions.core.data.misc, dispatch), + simpleBuyActions: bindActionCreators( + actions.components.simpleBuy, + dispatch + ) } } return { diff --git a/packages/blockchain-wallet-v4/src/network/api/simpleBuy/index.ts b/packages/blockchain-wallet-v4/src/network/api/simpleBuy/index.ts index d33ab6b2b28..ce4e94cfdd1 100644 --- a/packages/blockchain-wallet-v4/src/network/api/simpleBuy/index.ts +++ b/packages/blockchain-wallet-v4/src/network/api/simpleBuy/index.ts @@ -6,6 +6,7 @@ import { SBBalancesType, SBCardType, SBMoneyType, + SBOrderActionType, SBOrderType, SBPairsType, SBPairType, @@ -70,7 +71,7 @@ export default ({ const createSBOrder = ( pair: SBPairsType, - action: 'BUY' | 'SELL', + action: SBOrderActionType, pending: boolean, input: SBMoneyType, output: { @@ -211,7 +212,7 @@ export default ({ const getSBQuote = ( currencyPair: SBPairsType, - action: 'BUY' | 'SELL', + action: SBOrderActionType, amount: string ): SBQuoteType => authorizedGet({ diff --git a/packages/blockchain-wallet-v4/src/network/api/simpleBuy/types.ts b/packages/blockchain-wallet-v4/src/network/api/simpleBuy/types.ts index 07a4c7e03ef..e3ef2a1eebc 100644 --- a/packages/blockchain-wallet-v4/src/network/api/simpleBuy/types.ts +++ b/packages/blockchain-wallet-v4/src/network/api/simpleBuy/types.ts @@ -178,6 +178,7 @@ export type ISBBuyOrderType = { state: SBOrderStateType updatedAt: string } +export type SBOrderActionType = 'BUY' | 'SELL' export type SBBuyOrderType = ISBBuyOrderType & { inputCurrency: FiatType outputCurrency: CoinType @@ -200,7 +201,7 @@ export type SBOrderStateType = | 'EXPIRED' export type SBQuoteType = { - action: 'BUY' | 'SELL' + action: SBOrderActionType fee: string pair: SBPairsType rate: string