From 96d31dc5a09ad553f9d6bac3283ff48644fce912 Mon Sep 17 00:00:00 2001 From: leora Date: Tue, 17 Aug 2021 11:40:24 -0400 Subject: [PATCH 01/13] fix(save-session): sessionTokens save to state and cache clearing when browser is deauthed --- packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts | 1 + .../blockchain-wallet-v4-frontend/src/data/cache/reducers.js | 1 + .../blockchain-wallet-v4-frontend/src/data/session/slice.ts | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts b/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts index 5c5e9946f62..31b9bb5d3e7 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts @@ -586,6 +586,7 @@ export default ({ api, coreSagas, networks }) => { const email = (yield select(selectors.core.settings.getEmail)).getOrElse(undefined) const sessionToken = yield select(selectors.session.getSession, guid, email) yield call(api.deauthorizeBrowser, sessionToken) + yield put(actions.cache.removedStoredLogin()) yield put(actions.alerts.displaySuccess(C.DEAUTHORIZE_BROWSER_SUCCESS)) yield put(actions.cache.disconnectChannelPhone()) } catch (e) { diff --git a/packages/blockchain-wallet-v4-frontend/src/data/cache/reducers.js b/packages/blockchain-wallet-v4-frontend/src/data/cache/reducers.js index af5006ccc1f..670cb0b5557 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/cache/reducers.js +++ b/packages/blockchain-wallet-v4-frontend/src/data/cache/reducers.js @@ -34,6 +34,7 @@ const cache = (state = INITIAL_STATE, action) => { ...state, guidStored: undefined, lastEmail: undefined, + lastGuid: undefined, mobileConnected: undefined } } diff --git a/packages/blockchain-wallet-v4-frontend/src/data/session/slice.ts b/packages/blockchain-wallet-v4-frontend/src/data/session/slice.ts index e5ce89c4b03..bbbae899456 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/session/slice.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/session/slice.ts @@ -10,10 +10,10 @@ const sessionSlice = createSlice({ name: 'session', reducers: { removeSession: (state, action: PayloadAction) => { - state = dissoc(action.payload, state.sessions) + return dissoc(action.payload, state) }, saveSession: (state, action: PayloadAction<{ [key: string]: string }>) => { - state = mergeRight(state, action.payload) + return mergeRight(state, action.payload) } } }) From 0545687c4b72e04f404ab2810cba60714bc20367 Mon Sep 17 00:00:00 2001 From: blockdylanb <57680122+blockdylanb@users.noreply.github.com> Date: Tue, 17 Aug 2021 10:29:02 -0700 Subject: [PATCH 02/13] fix(recurring buy): fixes grammer and design issues with explainer text --- .../src/assets/locales/index.d.ts | 8 ++--- .../RecurringBuys/Notifications/index.tsx | 31 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) 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 c04e5939f20..308ae4db223 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 @@ -1232,11 +1232,11 @@ type MessagesType = { 'modals.recurringbuys.notification.page_2.title': 'The strategy is pretty simple' 'modals.recurringbuys.notification.page_2.description': 'Invest the same amount every week' - 'modals.recurringbuys.notification.page_3.title': 'When the price goes down,' - 'modals.recurringbuys.notification.page_3.description': 'You’ll buy more crypto.' + 'modals.recurringbuys.notification.page_3.title': 'When the price goes down' + 'modals.recurringbuys.notification.page_3.description': 'You’ll buy more crypto' - 'modals.recurringbuys.notification.page_4.title': 'When the price goes up,' - 'modals.recurringbuys.notification.page_4.description': 'You’ll buy less.' + 'modals.recurringbuys.notification.page_4.title': 'When the price goes up' + 'modals.recurringbuys.notification.page_4.description': 'You’ll buy less' 'modals.recurringbuys.notification.page_5.title': 'But does it work?' 'modals.recurringbuys.notification.page_5.description': 'Over the past 5 years, buying Bitcoin every week performed better than timing the market' diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Notifications/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Notifications/index.tsx index 33e5a8cee19..273e98332f7 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Notifications/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Notifications/index.tsx @@ -36,6 +36,7 @@ const SlideStart = styled(Slide)` const SlideContent = styled.div` padding: 0 40px; + text-align: center; ` const SyncIconWrapper = styled.div` @@ -94,13 +95,13 @@ class Notifications extends PureComponent { - + - + { - + - + { - + - + - + - + - + - + - + Date: Tue, 17 Aug 2021 11:36:23 -0700 Subject: [PATCH 03/13] fix(recurring buy): add one time option to frequency screen and fix back button --- .../src/components/Flyout/FrequencyScreen.tsx | 4 +--- .../src/data/components/recurringBuy/types.ts | 10 ++++++---- .../src/modals/SimpleBuy/index.tsx | 13 +++++++++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/FrequencyScreen.tsx b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/FrequencyScreen.tsx index 63e2da41f09..eef6e5e7f4d 100644 --- a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/FrequencyScreen.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/FrequencyScreen.tsx @@ -12,9 +12,7 @@ import { getPeriodSubTitleText, getPeriodTitleText } from './model' const FrequencyScreen = ({ children, headerAction, headerMode, setPeriod }: Props) => { // ONE_TIME is not a recurring buy option so take it out before displaying - const periods = Object.values(RecurringBuyPeriods).filter( - (p) => p !== RecurringBuyPeriods.ONE_TIME - ) + const periods = Object.values(RecurringBuyPeriods) const setPeriodCallback = useCallback( (period: RecurringBuyPeriods) => { return () => { diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/types.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/types.ts index a654a87f610..2c1122b1be8 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/types.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/types.ts @@ -52,13 +52,15 @@ export type RecurringBuyRegisteredList = { userId: string } +/* eslint-disable */ export enum RecurringBuyPeriods { - BI_WEEKLY = 'BI_WEEKLY', - DAILY = 'DAILY', - MONTHLY = 'MONTHLY', ONE_TIME = 'ONE_TIME', - WEEKLY = 'WEEKLY' + DAILY = 'DAILY', + WEEKLY = 'WEEKLY', + BI_WEEKLY = 'BI_WEEKLY', + MONTHLY = 'MONTHLY' } +/* eslint-enable */ export enum RecurringBuyFailureReasons { FAILED_BAD_FILL = 'FAILED_BAD_FILL', diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/index.tsx index 2651e68d2bf..08c7b2252d5 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/index.tsx @@ -18,7 +18,7 @@ import { actions, selectors } from 'data' import { getCoinFromPair, getFiatFromPair } from 'data/components/simpleBuy/model' import { GoalsType } from 'data/goals/types' import { RootState } from 'data/rootReducer' -import { BankStatusType, FastLinkType, ModalName } from 'data/types' +import { BankStatusType, FastLinkType, ModalName, RecurringBuyPeriods } from 'data/types' import ModalEnhancer from 'providers/ModalEnhancer' import { Loading as StdLoading, LoadingTextEnum } from '../components' @@ -51,6 +51,7 @@ class SimpleBuy extends PureComponent { constructor(props) { super(props) this.state = { show: false } + this.backToEnterAmount = this.backToEnterAmount.bind(this) this.handleFrequencySelection = this.handleFrequencySelection.bind(this) } @@ -80,7 +81,7 @@ class SimpleBuy extends PureComponent { }, duration) } - handleFrequencySelection = (period) => { + backToEnterAmount = () => { if (this.props.pair) { this.props.simpleBuyActions.setStep({ cryptoCurrency: getCoinFromPair(this.props.pair.pair), @@ -89,10 +90,14 @@ class SimpleBuy extends PureComponent { pair: this.props.pair, step: 'ENTER_AMOUNT' }) - this.props.formActions.change('simpleBuyCheckout', 'period', period) } } + handleFrequencySelection = (period?: RecurringBuyPeriods) => { + this.props.formActions.change('simpleBuyCheckout', 'period', period) + this.backToEnterAmount() + } + render() { return this.props.data.cata({ Failure: () => null, @@ -245,7 +250,7 @@ class SimpleBuy extends PureComponent { {this.props.step === 'FREQUENCY' && ( From fe55f38010df30af1108205d201de491270e5dcd Mon Sep 17 00:00:00 2001 From: blockdylanb <57680122+blockdylanb@users.noreply.github.com> Date: Tue, 17 Aug 2021 14:39:39 -0700 Subject: [PATCH 04/13] fix(recurring buy): adds sb updatedAt info to transaction list for non-finished orders for better context for users --- .../src/scenes/Transactions/SBOrderTx/model.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/SBOrderTx/model.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/SBOrderTx/model.tsx index f069183c338..e283ab47465 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/SBOrderTx/model.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/SBOrderTx/model.tsx @@ -112,7 +112,13 @@ export const Timestamp = (props: Props) => { case 'FINISHED': return default: - return + return ( + <> + +
+ + + ) } } From eba4f5ca4ae66107bad3dd2b90ce67927f910685 Mon Sep 17 00:00:00 2001 From: blockdylanb <57680122+blockdylanb@users.noreply.github.com> Date: Tue, 17 Aug 2021 15:43:36 -0700 Subject: [PATCH 05/13] fix(recurring buy): fix close and keep buttons on recurring buy details modal --- .storybook/main.js | 11 +---------- .storybook/preview.js | 10 ++++++++++ .../components/Flyout/RecurringBuyDetails.stories.tsx | 9 +++++++-- .../src/components/Flyout/RecurringBuyDetails.tsx | 5 ++++- .../components/Flyout/RecurringBuyRemoveConfirm.tsx | 5 ++++- .../src/modals/RecurringBuys/Details/index.tsx | 8 -------- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.storybook/main.js b/.storybook/main.js index 1f13f93180b..5b0827d66cf 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,19 +1,10 @@ module.exports = { - stories: ['../packages/blockchain-wallet-v4-frontend/src/components/**/*.stories.@(tsx)'], + stories: ['../packages/blockchain-wallet-v4-frontend/src/components/**/*.stories.@(js|jsx|ts|tsx)'], addons: [ '@storybook/addon-links', '@storybook/addon-essentials', 'storybook-dark-mode' ], - typescript: { - reactDocgen: 'react-docgen-typescript', - reactDocgenTypescriptOptions: { - compilerOptions: { - allowSyntheticDefaultImports: false, - esModuleInterop: false, - }, - } - }, refs: { 'new-core': { title: 'New Core Components', diff --git a/.storybook/preview.js b/.storybook/preview.js index fffc4c24fea..7d452a6c4ac 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -31,3 +31,13 @@ const withIconsAndFonts = () => (story) => { } addDecorator(withTheme()) addDecorator(withIconsAndFonts()) + +export const parameters = { + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +} diff --git a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.stories.tsx b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.stories.tsx index f26393a1baf..76fb69762ad 100644 --- a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.stories.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.stories.tsx @@ -1,5 +1,6 @@ import React from 'react' import { IntlProvider } from 'react-intl' +import { ComponentMeta, ComponentStory } from '@storybook/react' import { SBPaymentTypes } from '../../../../blockchain-wallet-v4/src/network/api/simpleBuy/types' import { RecurringBuyPeriods } from '../../data/types' @@ -33,6 +34,10 @@ export default { ) ], title: 'Flyouts/RecurringBuyDetails' -} +} as ComponentMeta -export const Default = (args) => +export const Template: ComponentStory = (args) => ( + +) + +export const Default = Template.bind({}) diff --git a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.tsx b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.tsx index 5a2ea994392..931552f5f97 100644 --- a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyDetails.tsx @@ -32,6 +32,9 @@ const RecurringBuyDetails = ({ removeClick, standardAmount }: Props) => { + const closeClickCallback = useCallback(() => { + closeClick() + }, [closeClick]) const removeClickCallback = useCallback(() => { removeClick(id) }, [removeClick, id]) @@ -46,7 +49,7 @@ const RecurringBuyDetails = ({ const amountString = `${Exchange.getSymbol(currency)}${standardAmount}` return ( -
+
diff --git a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyRemoveConfirm.tsx b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyRemoveConfirm.tsx index 3b145c64974..434393e3761 100644 --- a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyRemoveConfirm.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuyRemoveConfirm.tsx @@ -16,6 +16,9 @@ const RecurringBuyRemoveConfirm = memo( setSubmitting(true) removeClick(id) }, [setSubmitting, removeClick, id]) + const closeCallback = useCallback(() => { + close() + }, [close]) return ( @@ -62,7 +65,7 @@ const RecurringBuyRemoveConfirm = memo( data-e2e='removeRecurringBuyKeepButton' nature='light' fullwidth - onClick={close} + onClick={closeCallback} disabled={submitting} > diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Details/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Details/index.tsx index 26aac97c5a9..e71e654f253 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Details/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Details/index.tsx @@ -13,21 +13,13 @@ const Success = ({ activeDetails, close: closeClick, removeClick }: Props) => { if (!activeDetails) return null const { id, nextPayment, paymentMethod, period } = activeDetails const detailProps = { - // for future use closeClick, - complete: false, - crypto: activeDetails.destinationCurrency, - currency: activeDetails.inputCurrency, - id, - nextPayment, - paymentMethod, - period, removeClick, standardAmount: convertBaseToStandard(activeDetails.inputCurrency, activeDetails.inputValue) From 30cbbaad818060788f1ec7b67cd0d4b5c14f38a9 Mon Sep 17 00:00:00 2001 From: blockdylanb <57680122+blockdylanb@users.noreply.github.com> Date: Tue, 17 Aug 2021 15:52:22 -0700 Subject: [PATCH 06/13] fix(recurring buy): update learn more link --- .../src/components/Flyout/RecurringBuy/GettingStarted.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuy/GettingStarted.tsx b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuy/GettingStarted.tsx index 24ee6771aba..4f038b58a65 100644 --- a/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuy/GettingStarted.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/components/Flyout/RecurringBuy/GettingStarted.tsx @@ -69,7 +69,7 @@ const GettingStarted = ({ amount, close, nextStep, outputCurrency }: Props) => { size='14px' weight={500} target='_blank' - href='https://support.blockchain.com/hc/en-us/' + href='https://support.blockchain.com/hc/en-us/sections/4405090131860-Recurring-Buys-' > From 5ee8c846fe2617d7a27caaf79a721e08228422a5 Mon Sep 17 00:00:00 2001 From: plondon Date: Wed, 18 Aug 2021 11:17:27 -0400 Subject: [PATCH 07/13] fix(tx): scroll --- .../blockchain-wallet-v4/src/redux/data/coins/actions.ts | 7 +++++-- .../src/redux/data/coins/reducers.ts | 9 +++++++++ .../blockchain-wallet-v4/src/redux/data/coins/sagas.ts | 2 ++ .../blockchain-wallet-v4/src/redux/data/coins/types.ts | 8 ++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/blockchain-wallet-v4/src/redux/data/coins/actions.ts b/packages/blockchain-wallet-v4/src/redux/data/coins/actions.ts index 20f783ab9cc..bb6037a04f7 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/coins/actions.ts +++ b/packages/blockchain-wallet-v4/src/redux/data/coins/actions.ts @@ -41,7 +41,10 @@ export const fetchTransactionsSuccess = ( payload: { coin, isFinalPage, reset, transactions }, type: AT.FETCH_COINS_TRANSACTIONS_SUCCESS }) -export const transactionsAtBound = (payload) => ({ - payload, +export const transactionsAtBound = (coin: string, atBounds: boolean): CoinsActionTypes => ({ + payload: { + atBounds, + coin + }, type: AT.COINS_TRANSACTIONS_AT_BOUND }) diff --git a/packages/blockchain-wallet-v4/src/redux/data/coins/reducers.ts b/packages/blockchain-wallet-v4/src/redux/data/coins/reducers.ts index f2da00d7bcc..4310e8e2841 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/coins/reducers.ts +++ b/packages/blockchain-wallet-v4/src/redux/data/coins/reducers.ts @@ -66,6 +66,15 @@ export const coinsReducer = (state = INITIAL_STATE, action: CoinsActionTypes): C ] } } + case AT.COINS_TRANSACTIONS_AT_BOUND: { + return { + ...state, + transactions_at_bound: { + ...state.transactions_at_bound, + [action.payload.coin]: action.payload.atBounds + } + } + } default: { return state } diff --git a/packages/blockchain-wallet-v4/src/redux/data/coins/sagas.ts b/packages/blockchain-wallet-v4/src/redux/data/coins/sagas.ts index b74142dad68..05ec32ce878 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/coins/sagas.ts +++ b/packages/blockchain-wallet-v4/src/redux/data/coins/sagas.ts @@ -62,6 +62,8 @@ export default ({ api }: { api: APIType }) => { const page = flatten([txPage, custodialPage.orders]).sort((a, b) => { return moment(b.insertedAt).valueOf() - moment(a.insertedAt).valueOf() }) + const atBounds = page.length < TX_PER_PAGE + yield put(A.transactionsAtBound(payload.coin, atBounds)) yield put(A.fetchTransactionsSuccess(payload.coin, page, reset, true)) } catch (e) { const error = errorHandler(e) diff --git a/packages/blockchain-wallet-v4/src/redux/data/coins/types.ts b/packages/blockchain-wallet-v4/src/redux/data/coins/types.ts index b30d48f6cae..8f9dd7cd6de 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/coins/types.ts +++ b/packages/blockchain-wallet-v4/src/redux/data/coins/types.ts @@ -50,6 +50,13 @@ interface FetchTransactionsSuccessActionType { } type: typeof AT.FETCH_COINS_TRANSACTIONS_SUCCESS } +interface SetTransactionsAtBoundActionType { + payload: { + atBounds: boolean + coin: string + } + type: typeof AT.COINS_TRANSACTIONS_AT_BOUND +} export type CoinsActionTypes = | FetchCoinsFailureActionType @@ -58,3 +65,4 @@ export type CoinsActionTypes = | FetchTransactionsFailureActionType | FetchTransactionsLoadingActionType | FetchTransactionsSuccessActionType + | SetTransactionsAtBoundActionType From 109f0546856f40561670129309c9bbb803d02bdf Mon Sep 17 00:00:00 2001 From: blockdylanb <57680122+blockdylanb@users.noreply.github.com> Date: Wed, 18 Aug 2021 14:34:29 -0700 Subject: [PATCH 08/13] fix(recurring buy): only show the first time buyer flow if its truly the users first purchase --- .../src/modals/SimpleBuy/OrderSummary/index.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/OrderSummary/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/OrderSummary/index.tsx index 80da3a84e8b..710bd46bbf6 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/OrderSummary/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/SimpleBuy/OrderSummary/index.tsx @@ -40,12 +40,11 @@ class OrderSummary extends PureComponent { } okButtonHandler = () => { - // first time buyers have 1 tx at this point so and RB is set to one time buy so send them to RB walkthrough flow - // FIXME: The logic on the line below is hacked to be wrong so I can test. + // first time buyers have 1 tx at this point and RB is set to one time buy so send them to RB walkthrough flow if ( this.props.isRecurringBuy && - this.props.orders.length > 1 && - this.props.order.period !== RecurringBuyPeriods.ONE_TIME && + this.props.orders.length <= 1 && + this.props.order.period === RecurringBuyPeriods.ONE_TIME && this.props.hasQuote ) { this.props.recurringBuyActions.showModal({ origin: 'SimpleBuyOrderSummary' }) From 48bf83ebbff1ad41aa8d51934ee9dd45252e2341 Mon Sep 17 00:00:00 2001 From: Milan Date: Wed, 18 Aug 2021 23:49:01 +0200 Subject: [PATCH 09/13] feat(signup): put country logic on signup under feature flag --- config/mocks/wallet-options-v4.json | 3 +- .../src/data/auth/sagas.ts | 5 +- .../Signup/components/SignupForm/index.tsx | 81 ++++++++++--------- .../src/scenes/Signup/index.tsx | 10 ++- .../src/redux/walletOptions/selectors.ts | 7 ++ 5 files changed, 65 insertions(+), 41 deletions(-) diff --git a/config/mocks/wallet-options-v4.json b/config/mocks/wallet-options-v4.json index 63377243583..a147f2f0c88 100644 --- a/config/mocks/wallet-options-v4.json +++ b/config/mocks/wallet-options-v4.json @@ -23,7 +23,8 @@ "legacyMagicEmailLink": true, "legacyMobilePairing": false, "legacyWalletRecovery": false, - "recurringBuys": true + "recurringBuys": true, + "signupCountry": false } } }, diff --git a/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts b/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts index 31b9bb5d3e7..6d0f4cf9d99 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts @@ -311,7 +311,10 @@ export default ({ api, coreSagas, networks }) => { yield put(actions.components.swap.fetchTrades()) // check/update btc account names yield call(coreSagas.wallet.checkAndUpdateWalletNames) - if (firstLogin) { + const isSignupCountry = (yield select( + selectors.core.walletOptions.getFeatureSignupCountry + )).getOrElse(false) + if (firstLogin && isSignupCountry) { // create nabu user yield call(createUser) // store initial address in case of US state we add prefix diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx index 14f67583ec3..811f896f864 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx @@ -70,8 +70,15 @@ const scrollToPassword = () => scrollToId('password') const scrollToSecondPassword = () => scrollToId('confirmationPassword') const SignupForm = (props: InjectedFormProps<{}, SubviewProps> & SubviewProps) => { - const { formValues, invalid, isFormSubmitting, onCountrySelect, onSignupSubmit, showState } = - props + const { + formValues, + invalid, + isFormSubmitting, + isSignupCountry, + onCountrySelect, + onSignupSubmit, + showState + } = props const { password = '' } = formValues || {} const passwordScore = window.zxcvbn ? window.zxcvbn(password).score : 0 @@ -164,48 +171,50 @@ const SignupForm = (props: InjectedFormProps<{}, SubviewProps> & SubviewProps) = /> - - - - - - + + - } - /> - - {showState ? ( - + val && val.code} + data-e2e='selectCountryDropdown' + name='country' + validate={required} + component={SelectBoxCountry} + menuPlacement='auto' + // @ts-ignore + onChange={onCountrySelect} label={ } /> - - ) : null} - + + {showState ? ( + + val && val.code} + label={ + + } + /> + + ) : null} + + )} diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx index 83aeb6d10ac..e4bb9625aa6 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx @@ -8,7 +8,6 @@ import styled from 'styled-components' import { Remote } from 'blockchain-wallet-v4/src' import { RemoteDataType } from 'blockchain-wallet-v4/src/types' import { actions, selectors } from 'data' -import { GoalsType } from 'data/goals/types' import { RootState } from 'data/rootReducer' import BuyGoal from './BuyGoal' @@ -62,13 +61,13 @@ class SignupContainer extends React.PureComponent< } render() { - const { goals, isLoadingR, userGeoData } = this.props + const { goals, isLoadingR, isSignupCountry, userGeoData } = this.props const isFormSubmitting = Remote.Loading.is(isLoadingR) // pull email from simple buy goal if it exists const email = pathOr('', ['data', 'email'], find(propEq('name', 'simpleBuy'), goals)) const signupInitialValues = (email ? { email } : {}) as SignupFormInitValuesType - if (userGeoData?.countryCode) { + if (userGeoData?.countryCode && isSignupCountry) { signupInitialValues.country = userGeoData.countryCode } const isLinkAccountGoal = !!find(propEq('name', 'linkAccount'), goals) @@ -78,6 +77,7 @@ class SignupContainer extends React.PureComponent< initialValues: signupInitialValues, isFormSubmitting, isLinkAccountGoal, + isSignupCountry, onCountrySelect: this.onCountryChange, onSignupSubmit: this.onSubmit, showForm: this.state.showForm, @@ -100,6 +100,9 @@ const mapStateToProps = (state: RootState): LinkStatePropsType => ({ formValues: selectors.form.getFormValues(SIGNUP_FORM)(state) as SignupFormType, goals: selectors.goals.getGoals(state) as GoalDataType, isLoadingR: selectors.auth.getRegistering(state) as RemoteDataType, + isSignupCountry: selectors.core.walletOptions + .getFeatureSignupCountry(state) + .getOrElse(false) as boolean, language: selectors.preferences.getLanguage(state), search: selectors.router.getSearch(state) as string, userGeoData: selectors.auth.getUserGeoData(state) as GeoLocationType @@ -118,6 +121,7 @@ type LinkStatePropsType = { formValues: SignupFormType goals: GoalDataType isLoadingR: RemoteDataType + isSignupCountry: boolean language: string search: string userGeoData: GeoLocationType diff --git a/packages/blockchain-wallet-v4/src/redux/walletOptions/selectors.ts b/packages/blockchain-wallet-v4/src/redux/walletOptions/selectors.ts index a0aed996ff9..15803e0b47b 100755 --- a/packages/blockchain-wallet-v4/src/redux/walletOptions/selectors.ts +++ b/packages/blockchain-wallet-v4/src/redux/walletOptions/selectors.ts @@ -1,6 +1,7 @@ import { path, prop } from 'ramda' import { /* AccountTokensBalancesResponseType, */ RemoteDataType } from 'core/types' +// eslint-disable-next-line import/no-extraneous-dependencies import { RootState } from 'data/rootReducer' import { WalletOptionsType } from './types' @@ -21,7 +22,9 @@ export const getAnalyticsSiteId = (state) => export const getAnnouncements = (state) => getWebOptions(state).map(path(['application', 'announcements'])) +// eslint-disable-next-line export const getXlmSendTimeOutSeconds = (state) => 600 +// eslint-disable-next-line export const getXlmExchangeAddresses = (state) => [] // domains @@ -55,3 +58,7 @@ export const getFeatureLegacyWalletRecovery = (state: RootState) => // legacy magic email link export const getFeatureLegacyMagicEmailLink = (state: RootState) => getWebOptions(state).map(path(['featureFlags', 'legacyMagicEmailLink'])) + +// signup country feature flag +export const getFeatureSignupCountry = (state: RootState) => + getWebOptions(state).map(path(['featureFlags', 'signupCountry'])) From 856a3c3cc50797800119f65b2a8f71c22847f310 Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 19 Aug 2021 15:47:56 +0200 Subject: [PATCH 10/13] feat(signup): renamed variable to be signupCountryEnabled --- .../src/data/auth/sagas.ts | 4 ++-- .../scenes/Signup/components/SignupForm/index.tsx | 6 +++--- .../src/scenes/Signup/index.tsx | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts b/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts index 6d0f4cf9d99..0ae08e61b90 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.ts @@ -311,10 +311,10 @@ export default ({ api, coreSagas, networks }) => { yield put(actions.components.swap.fetchTrades()) // check/update btc account names yield call(coreSagas.wallet.checkAndUpdateWalletNames) - const isSignupCountry = (yield select( + const signupCountryEnabled = (yield select( selectors.core.walletOptions.getFeatureSignupCountry )).getOrElse(false) - if (firstLogin && isSignupCountry) { + if (firstLogin && signupCountryEnabled) { // create nabu user yield call(createUser) // store initial address in case of US state we add prefix diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx index 811f896f864..abfa1803a77 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/components/SignupForm/index.tsx @@ -74,10 +74,10 @@ const SignupForm = (props: InjectedFormProps<{}, SubviewProps> & SubviewProps) = formValues, invalid, isFormSubmitting, - isSignupCountry, onCountrySelect, onSignupSubmit, - showState + showState, + signupCountryEnabled } = props const { password = '' } = formValues || {} const passwordScore = window.zxcvbn ? window.zxcvbn(password).score : 0 @@ -171,7 +171,7 @@ const SignupForm = (props: InjectedFormProps<{}, SubviewProps> & SubviewProps) = /> - {isSignupCountry && ( + {signupCountryEnabled && ( diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx index e4bb9625aa6..de23700e8f0 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Signup/index.tsx @@ -61,13 +61,13 @@ class SignupContainer extends React.PureComponent< } render() { - const { goals, isLoadingR, isSignupCountry, userGeoData } = this.props + const { goals, isLoadingR, signupCountryEnabled, userGeoData } = this.props const isFormSubmitting = Remote.Loading.is(isLoadingR) // pull email from simple buy goal if it exists const email = pathOr('', ['data', 'email'], find(propEq('name', 'simpleBuy'), goals)) const signupInitialValues = (email ? { email } : {}) as SignupFormInitValuesType - if (userGeoData?.countryCode && isSignupCountry) { + if (userGeoData?.countryCode && signupCountryEnabled) { signupInitialValues.country = userGeoData.countryCode } const isLinkAccountGoal = !!find(propEq('name', 'linkAccount'), goals) @@ -77,11 +77,11 @@ class SignupContainer extends React.PureComponent< initialValues: signupInitialValues, isFormSubmitting, isLinkAccountGoal, - isSignupCountry, onCountrySelect: this.onCountryChange, onSignupSubmit: this.onSubmit, showForm: this.state.showForm, showState: this.state.showState, + signupCountryEnabled, toggleSignupFormVisibility: this.toggleSignupFormVisibility, ...this.props } @@ -100,11 +100,11 @@ const mapStateToProps = (state: RootState): LinkStatePropsType => ({ formValues: selectors.form.getFormValues(SIGNUP_FORM)(state) as SignupFormType, goals: selectors.goals.getGoals(state) as GoalDataType, isLoadingR: selectors.auth.getRegistering(state) as RemoteDataType, - isSignupCountry: selectors.core.walletOptions - .getFeatureSignupCountry(state) - .getOrElse(false) as boolean, language: selectors.preferences.getLanguage(state), search: selectors.router.getSearch(state) as string, + signupCountryEnabled: selectors.core.walletOptions + .getFeatureSignupCountry(state) + .getOrElse(false) as boolean, userGeoData: selectors.auth.getUserGeoData(state) as GeoLocationType }) @@ -121,9 +121,9 @@ type LinkStatePropsType = { formValues: SignupFormType goals: GoalDataType isLoadingR: RemoteDataType - isSignupCountry: boolean language: string search: string + signupCountryEnabled: boolean userGeoData: GeoLocationType } type StateProps = { From 255acdca933ffa00dc5e45d821b8f6575e896ddb Mon Sep 17 00:00:00 2001 From: blockdylanb <57680122+blockdylanb@users.noreply.github.com> Date: Thu, 19 Aug 2021 08:47:11 -0700 Subject: [PATCH 11/13] fix(simple buy): fixes issue with calling type of undefined error --- .../src/data/components/recurringBuy/selectors.ts | 7 +++++-- .../src/modals/RecurringBuys/Scheduler/index.tsx | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts index 6eeb0e5febf..8640412cd87 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts @@ -1,5 +1,6 @@ import { createSelector } from '@reduxjs/toolkit' +import { SBPaymentMethodsType, SBPaymentMethodType } from 'core/types' import { RootState } from 'data/rootReducer' import { RecurringBuyPeriods } from './types' @@ -10,10 +11,12 @@ export const getMethods = (state: RootState) => state.components.recurringBuy.me export const getPeriod = (state: RootState) => state.components.recurringBuy.period export const getRegisteredList = (state: RootState) => state.components.recurringBuy.registeredList -export const isAvailableMethod = (method) => +export const isAvailableMethod = (method?: SBPaymentMethodType) => createSelector( getMethods, - (methodsR) => methodsR.getOrElse([]).filter((m) => m === method.type).length > 0 + (methodsR) => + methodsR.getOrElse([]).filter((m) => m === (method?.type as unknown as RecurringBuyPeriods)) + .length > 0 ) export const getRegisteredListByCoin = (coin) => diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Scheduler/index.tsx b/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Scheduler/index.tsx index 8caa99ba57d..1d13d5f1ed0 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Scheduler/index.tsx +++ b/packages/blockchain-wallet-v4-frontend/src/modals/RecurringBuys/Scheduler/index.tsx @@ -20,7 +20,7 @@ const SchedulerContainer = (props: Props) => { return null } -const mapStateToProps = (state, ownProps) => ({ +const mapStateToProps = (state, ownProps: OwnProps) => ({ availableMethods: selectors.components.recurringBuy.isAvailableMethod(ownProps.method)(state) }) From 8aa81488fa5595008555a6fd822081b61ccc83e0 Mon Sep 17 00:00:00 2001 From: plondon Date: Thu, 19 Aug 2021 14:35:48 -0400 Subject: [PATCH 12/13] feat(error boundary): use error stack instead of component stack --- .../data/components/recurringBuy/selectors.ts | 6 +- .../providers/ErrorBoundaryProvider/index.js | 60 ------------------- .../providers/ErrorBoundaryProvider/index.tsx | 55 +++++++++++++++++ .../{template.js => template.tsx} | 38 ++++-------- 4 files changed, 70 insertions(+), 89 deletions(-) delete mode 100644 packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.js create mode 100644 packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.tsx rename packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/{template.js => template.tsx} (69%) diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts index 8640412cd87..01f16e3a75a 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts @@ -11,12 +11,10 @@ export const getMethods = (state: RootState) => state.components.recurringBuy.me export const getPeriod = (state: RootState) => state.components.recurringBuy.period export const getRegisteredList = (state: RootState) => state.components.recurringBuy.registeredList -export const isAvailableMethod = (method?: SBPaymentMethodType) => +export const isAvailableMethod = (method) => createSelector( getMethods, - (methodsR) => - methodsR.getOrElse([]).filter((m) => m === (method?.type as unknown as RecurringBuyPeriods)) - .length > 0 + (methodsR) => methodsR.getOrElse([]).filter((m) => m === method.type).length > 0 ) export const getRegisteredListByCoin = (coin) => diff --git a/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.js b/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.js deleted file mode 100644 index e78d9326888..00000000000 --- a/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react' -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { bindActionCreators } from 'redux' - -import { actions } from 'data' - -import { selectors } from '../../data' -import ErrorModal from './template' - -class ErrorBoundary extends React.Component { - state = { - error: null, - errorInfo: null - } - - componentDidCatch(error, info) { - this.setState({ - error: error, - errorInfo: info - }) - } - - onSubmit = () => { - this.setState({ error: null, errorInfo: null }) - if (this.props.isAuthenticated) { - this.props.history.push('/home') - } else { - this.props.history.push('/login') - window.location.reload(true) - } - } - - render() { - if (this.state.error) { - return ( - - ) - } - return this.props.children - } -} - -const mapStateToProps = state => ({ - isAuthenticated: selectors.auth.isAuthenticated(state) -}) - -const mapDispatchToProps = dispatch => ({ - authActions: bindActionCreators(actions.auth, dispatch), - routerActions: bindActionCreators(actions.router, dispatch) -}) - -export default withRouter( - connect(mapStateToProps, mapDispatchToProps)(ErrorBoundary) -) diff --git a/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.tsx b/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.tsx new file mode 100644 index 00000000000..750fc70d1a4 --- /dev/null +++ b/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/index.tsx @@ -0,0 +1,55 @@ +import React from 'react' +import { connect, ConnectedProps } from 'react-redux' +import { withRouter } from 'react-router-dom' +import { bindActionCreators } from 'redux' + +import { actions, selectors } from 'data' + +import ErrorModal from './template' + +class ErrorBoundary extends React.Component { + constructor(props) { + super(props) + this.state = { + error: null + } + } + + componentDidCatch(error) { + this.setState({ + error + }) + } + + onSubmit = () => { + this.setState({ error: null }) + if (this.props.isAuthenticated) { + this.props.history.push('/home') + } else { + this.props.history.push('/login') + window.location.reload(true) + } + } + + render() { + if (this.state.error) { + return + } + return this.props.children + } +} + +const mapStateToProps = (state) => ({ + isAuthenticated: selectors.auth.isAuthenticated(state) +}) + +const mapDispatchToProps = (dispatch) => ({ + authActions: bindActionCreators(actions.auth, dispatch), + routerActions: bindActionCreators(actions.router, dispatch) +}) + +const connector = connect(mapStateToProps, mapDispatchToProps) + +type Props = ConnectedProps & { history: { push: (path: string) => void } } + +export default withRouter(connector(ErrorBoundary)) diff --git a/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/template.js b/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/template.tsx similarity index 69% rename from packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/template.js rename to packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/template.tsx index e059909c872..dcd507ef89a 100644 --- a/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/template.js +++ b/packages/blockchain-wallet-v4-frontend/src/providers/ErrorBoundaryProvider/template.tsx @@ -20,9 +20,9 @@ const TitleGroup = styled(TextGroup)` justify-content: center; align-items: center; ` -const ErrorDetails = styled.details` - margin-top: 20px; - white-space: pre-wrap; +const ErrorDetails = styled.div` + margin-top: 8px; + white-space: pre-line; max-height: 350px; overflow: scroll; ::-webkit-scrollbar { @@ -38,25 +38,15 @@ const ErrorDetails = styled.details` } ` -const ErrorBoundary = props => { - const { error, errorInfo, onSubmit, position, total } = props +const ErrorBoundary = (props: { error: TypeError; onSubmit: any }) => { + const { error, onSubmit } = props return ( - + - + { - + - - - Error Details - {error && error.toString()} -
- {errorInfo.componentStack} -
+ + Error Details: + + + {error && error.stack}
From b45ecee4e3354220159c4fdfd84270e44621a65d Mon Sep 17 00:00:00 2001 From: plondon Date: Thu, 19 Aug 2021 14:44:04 -0400 Subject: [PATCH 13/13] fix(error): remove actual error --- .../src/data/components/recurringBuy/selectors.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts index 01f16e3a75a..8640412cd87 100644 --- a/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts +++ b/packages/blockchain-wallet-v4-frontend/src/data/components/recurringBuy/selectors.ts @@ -11,10 +11,12 @@ export const getMethods = (state: RootState) => state.components.recurringBuy.me export const getPeriod = (state: RootState) => state.components.recurringBuy.period export const getRegisteredList = (state: RootState) => state.components.recurringBuy.registeredList -export const isAvailableMethod = (method) => +export const isAvailableMethod = (method?: SBPaymentMethodType) => createSelector( getMethods, - (methodsR) => methodsR.getOrElse([]).filter((m) => m === method.type).length > 0 + (methodsR) => + methodsR.getOrElse([]).filter((m) => m === (method?.type as unknown as RecurringBuyPeriods)) + .length > 0 ) export const getRegisteredListByCoin = (coin) =>