From 646beb01e904c712d64056a3f74462a3de80b1b3 Mon Sep 17 00:00:00 2001 From: yushi Date: Mon, 10 Jun 2024 20:30:12 +0800 Subject: [PATCH 01/16] finish the sell ADA on Encryptus flow --- .../wallet/send/TransactionSuccessDialog.js | 17 ++++++++++-- .../app/containers/wallet/WalletSendPage.js | 12 +++++++-- .../app/stores/toplevel/LoadingStore.js | 25 +++++++++++++++++ .../app/stores/toplevel/WalletStore.js | 27 +++++++++++++++++++ .../chrome/content-scripts/inject.js | 9 +++---- .../chrome/extension/background.js | 24 +++++++++++++++++ 6 files changed, 104 insertions(+), 10 deletions(-) diff --git a/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js b/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js index f8875f1e42..1d8b99d85a 100644 --- a/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js +++ b/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js @@ -20,11 +20,20 @@ const messages = defineMessages({ id: 'wallet.transaction.success.explanation', defaultMessage: '!!!Check this transaction in the list of wallet transactions', }, + sellSendDone: { + id: 'wallet.transactions.success.sell', + defaultMessage: '!!!Transaction has been submitted', + }, + goToExchange: { + id: 'wallet.transactions.success.button.encryptus', + defaultMessage: '!!!Go to the exchange page', + }, }); type Props = {| +onClose: void => PossiblyAsync, +classicTheme: boolean, + +process: 'for-sell' | 'normal', |}; @observer @@ -41,7 +50,9 @@ export default class TransactionSuccessDialog extends Component { title={intl.formatMessage(messages.title)} actions={[ { - label: intl.formatMessage(globalMessages.goToTransactions), + label: intl.formatMessage( + this.props.process === 'normal' ? globalMessages.goToTransactions : messages.goToExchange + ), onClick: this.props.onClose, primary: true, }, @@ -58,7 +69,9 @@ export default class TransactionSuccessDialog extends Component { textAlign="center" maxWidth="400px" > - {intl.formatMessage(messages.explanation)} + {intl.formatMessage( + this.props.process === 'normal' ? messages.explanation: messages.sellSendDone + )} diff --git a/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js b/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js index 07b7a6a8a0..2765f1e327 100644 --- a/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js +++ b/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js @@ -74,8 +74,13 @@ class WalletSendPage extends Component { @observable showSupportedAddressDomainBanner: boolean = true; closeTransactionSuccessDialog: void => void = () => { - this.props.actions.dialogs.closeActiveDialog.trigger(); - this.props.actions.router.goToRoute.trigger({ route: ROUTES.WALLETS.TRANSACTIONS }); + const redirect = this.props.stores.loading.sellAdaParams?.redirect; + if (redirect) { + window.document.location = redirect; + } else { + this.props.actions.dialogs.closeActiveDialog.trigger(); + this.props.actions.router.goToRoute.trigger({ route: ROUTES.WALLETS.TRANSACTIONS }); + } }; openTransactionSuccessDialog: void => void = () => { @@ -293,8 +298,11 @@ class WalletSendPage extends Component { return this.noCloudWarningDialog(); } if (uiDialogs.isOpen(TransactionSuccessDialog)) { + const process = this.props.stores.loading.sellAdaParams?.redirect ? + 'for-sell' : 'normal'; return ( diff --git a/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js b/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js index ce8427f361..1e870cbb12 100644 --- a/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js +++ b/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js @@ -17,6 +17,12 @@ import { } from '../../utils/tabManager'; import type { lf$Database } from 'lovefield'; +type SellAdaParamsType = {| + addr: string, + redirect: string, + amount: string, +|}; + export default class LoadingStore extends BaseLoadingStore { /** * null if app not opened from URI Scheme OR URI scheme was invalid @@ -24,6 +30,7 @@ export default class LoadingStore extends BaseLoadingStore { + this._uriParams = uriParams; + }); + } + @computed get shouldRedirect(): boolean { return this._shouldRedirect; } diff --git a/packages/yoroi-extension/app/stores/toplevel/WalletStore.js b/packages/yoroi-extension/app/stores/toplevel/WalletStore.js index f6f1ba663f..84780f4e3f 100644 --- a/packages/yoroi-extension/app/stores/toplevel/WalletStore.js +++ b/packages/yoroi-extension/app/stores/toplevel/WalletStore.js @@ -31,6 +31,8 @@ import { createProblematicWalletDialog } from '../../containers/wallet/dialogs/P import type { ActionsMap } from '../../actions/index'; import type { StoresMap } from '../index'; import { getWalletChecksum } from '../../api/export/utils'; +import { MultiToken } from '../../api/common/lib/MultiToken'; +import { BigNumber } from 'bignumber.js'; type GroupedWallets = {| publicDerivers: Array>, @@ -342,6 +344,31 @@ export default class WalletStore extends Store { this.actions.serverConnection.parallelSyncStateChange.listen(() => { this._startRefreshAllWallets(); }); + // todo: under the current architecture, the delay is required otherwise if we go to the send page + // immediately it would crash, but soon we will migrate to new architecture which allows for + // immediate transition + const { sellAdaParams } = this.stores.loading; + if (sellAdaParams) { + const { selected } = this; + if (!selected) { + throw new Error('unexpected'); + } + const defaultToken = selected.getParent().getDefaultToken(); + this.stores.loading.setUriParams({ + address: sellAdaParams.addr, + amount: new MultiToken( + [{ + identifier: defaultToken.defaultIdentifier, + networkId: defaultToken.defaultNetworkId, + amount: (new BigNumber(sellAdaParams.amount)).shiftedBy(6), + }], + defaultToken, + ), + }); + this.actions.router.goToRoute.trigger({ + route: ROUTES.WALLETS.SEND, + }); + } }, 50); // let the UI render first so that the loading process is perceived faster }; diff --git a/packages/yoroi-extension/chrome/content-scripts/inject.js b/packages/yoroi-extension/chrome/content-scripts/inject.js index 5bb82be5a0..f73f62692b 100644 --- a/packages/yoroi-extension/chrome/content-scripts/inject.js +++ b/packages/yoroi-extension/chrome/content-scripts/inject.js @@ -239,15 +239,12 @@ async function convertImgToBase64(origin, urls) { return reader.result; } -// relay Banxa callback to the extension tab +// relay Banxa/Encryptus callback to the extension tab window.addEventListener('message', function (event) { if ( event.source === window && - ( - event.origin === 'http://localhost:8000' || - event.origin === 'https://ramp-redirect.yoroiwallet.com' - ) && - event.data?.type === 'banxa callback' + /https:\/\/([a-z-]+\.)?yoroi-?wallet\.com/.test(event.origin) && + event.data?.type === 'exchange callback' ) { chrome.runtime.sendMessage(event.data); } diff --git a/packages/yoroi-extension/chrome/extension/background.js b/packages/yoroi-extension/chrome/extension/background.js index f89501f21d..b2c8ddbaff 100644 --- a/packages/yoroi-extension/chrome/extension/background.js +++ b/packages/yoroi-extension/chrome/extension/background.js @@ -857,6 +857,9 @@ const yoroiMessageHandler = async ( chrome.runtime.onMessage.addListener( (message, sender, sendResponse) => { + if (handleExchangeRedirectMessage(message, sender)) { + return; + } if (isYoroiMessage(message)) { // Returning `true` is required by Firefox, see: // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage @@ -1783,3 +1786,24 @@ async function transformCardanoUtxos( }; }); } + +function handleExchangeRedirectMessage(message, sender) { + const url = new URL(sender.url); + if (url.hostname === 'yoroi-wallet.com') { + const { searchParams } = url; + const cardanoLink = decodeURIComponent(searchParams.get('link') || ''); + const m = cardanoLink.match(/web\+cardano:([a-z0-9]+)\?amount=([0-9\.]+)/); + if (!m) { + return; + } + const addr = m[1]; + const amount = m[2]; + const redirectTo = searchParams.get('redirectTo'); + // $FlowFixMe[prop-missing] flow doesn't know replaceAll + const redirectToFixed = redirectTo?.replaceAll('%253A', ':')?.replaceAll('%252F', '/') || ''; + chrome.tabs.remove(sender.tab.id); + const extensionUrl = `main_window.html?action=sell-ada&addr=${addr}&amount=${amount}` + + `&redirect=${encodeURIComponent(redirectToFixed)}`; + chrome.tabs.create({ url: extensionUrl }); + } +} From 5a2acb82321bdaea4782646e08c9668fcda76177 Mon Sep 17 00:00:00 2001 From: yushi Date: Mon, 10 Jun 2024 21:03:04 +0800 Subject: [PATCH 02/16] add translation text --- .../app/components/wallet/send/TransactionSuccessDialog.js | 2 +- packages/yoroi-extension/app/i18n/locales/en-US.json | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js b/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js index 1d8b99d85a..ed159558e6 100644 --- a/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js +++ b/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js @@ -25,7 +25,7 @@ const messages = defineMessages({ defaultMessage: '!!!Transaction has been submitted', }, goToExchange: { - id: 'wallet.transactions.success.button.encryptus', + id: 'wallet.transactions.success.button.exchange', defaultMessage: '!!!Go to the exchange page', }, }); diff --git a/packages/yoroi-extension/app/i18n/locales/en-US.json b/packages/yoroi-extension/app/i18n/locales/en-US.json index d6106e1042..a711e96e41 100644 --- a/packages/yoroi-extension/app/i18n/locales/en-US.json +++ b/packages/yoroi-extension/app/i18n/locales/en-US.json @@ -949,6 +949,8 @@ "wallet.transaction.type.stakeKeyRegistered": "Staking key registered", "wallet.transaction.withdraw": "Withdraw", "wallet.transaction.withdrawalsLabel": "Withdrawals", + "wallet.transactions.success.button.exchange": "Go to the exchange page", + "wallet.transactions.success.sell": "!!!Transaction has been submitted", "wallet.transfer.deregister.deregister": "Deregister", "wallet.transfer.deregister.keep": "Keep registered", "wallet.transfer.deregister.line1": "When withdrawing rewards, you also have the option to deregister the staking key", From 5eafedf03b84a12036b602e9a3dfa37f7d099948 Mon Sep 17 00:00:00 2001 From: yushi Date: Mon, 10 Jun 2024 21:07:23 +0800 Subject: [PATCH 03/16] change button text to buy/sell --- .../yoroi-extension/app/components/topbar/BuySellAdaButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js b/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js index 3ed4b7bbb2..726e07719d 100644 --- a/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js +++ b/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js @@ -46,7 +46,7 @@ class BuySellAdaButton extends Component { variant="secondary" onClick={() => this.props.onBuySellClick()} > - {intl.formatMessage(globalMessages.buyAda)} + {intl.formatMessage(globalMessages.buySellAda)} ); From 3e8aad93f793b1705a898d5bd302db36cb082554 Mon Sep 17 00:00:00 2001 From: yushi Date: Tue, 11 Jun 2024 14:07:14 +0800 Subject: [PATCH 04/16] handle exchange URL generation error --- .../app/components/buySell/BuySellDialog.js | 85 ++++++++++++++++--- .../app/containers/NavBarContainerRevamp.js | 2 +- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 967adfe964..e3e32c9179 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -66,13 +66,15 @@ const messages = defineMessages({ type Props = {| +onCancel: void => void, +onExchangeCallback: void => void, - +currentBalanceAda: string, + +currentBalanceAda: BigNumber, +receiveAdaAddressPromise: Promise, |}; type State = {| +isBuying: boolean, - +error: null | 'lessThanBuyMinimum' | 'notEnoughBalance' | 'lessThanSellMinimum', + +inputError: null | 'lessThanBuyMinimum' | 'notEnoughBalance' | 'lessThanSellMinimum', + // 'popOutDialog' is not really an error but is an temporary state + +urlGenenerationError: null | 'longLoading' | 'timeout' | 'fail', +amountAda: string, +isSubmitting: boolean, |}; @@ -151,6 +153,9 @@ const Disclaimer = styled(Box)({ padding: 'var(--spacing-12, 12px) var(--spacing-16, 16px) var(--spacing-16, 16px) var(--spacing-16, 16px)' }); +const URL_GENERATION_LONG_LOADING_TIMEOUT = 2 * 1000; +const URL_GENERATION_TIMEOUT = 30 * 1000; + @observer export default class BuySellDialog extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { @@ -159,11 +164,14 @@ export default class BuySellDialog extends Component { state: State = { isBuying: true, - error: null, + inputError: null, + urlGenenerationError: null, amountAda: '', isSubmitting: false, }; + urlGenerationTimeout: null | number = null; + onSubmit: () => Promise = async () => { const { state, props } = this; @@ -200,7 +208,34 @@ export default class BuySellDialog extends Component { } } - const url = await manager.referralLink.create(params); + this.urlGenerationTimeout = setTimeout( + () => { + this.setState({ urlGenerationError: 'longLoading' }); + this.urlGenerationTimeout = setTimeout( + () => { + this.setState({ urlGenrationError: 'timeout' }); + }, + URL_GENERATION_TIMEOUT - URL_GENERATION_LONG_LOADING_TIMEOUT + ); + }, + URL_GENERATION_LONG_LOADING_TIMEOUT + ); + + let url; + try { + url = await manager.referralLink.create(params); + } catch { + this.setState({ urlGenerationError: 'fail' }); + return; + } finally { + cancelTimeout(this.urlGenerationTimeout); + } + + // if timeout already happened, give up the process + if (this.state.urlGenerationError === 'timeout') { + return; + } + this.setState({ urlGenrationError: null }); const self = this; chrome.tabs.create({ url: url.href }, (exchangePageTab) => { @@ -226,7 +261,7 @@ export default class BuySellDialog extends Component { return; } - const error = (() => { + const inputError = (() => { if (value === '') { return null; } @@ -248,7 +283,7 @@ export default class BuySellDialog extends Component { return null; })(); - this.setState({ amountAda: value, error }); + this.setState({ amountAda: value, inputError }); } renderBuySell(): Node { @@ -263,11 +298,11 @@ export default class BuySellDialog extends Component { // set a place holder so that when it becomes an error message, the height doesn't change let helperText = ' '; - if (state.error === 'lessThanBuyMinimum') { + if (state.inputError === 'lessThanBuyMinimum') { helperText = intl.formatMessage(messages.lessThanMinimum, { amount: MINIMUM_BUY_ADA.toString() }); - } else if (state.error === 'lessThanSellMinimum') { + } else if (state.inputError === 'lessThanSellMinimum') { helperText = intl.formatMessage(messages.lessThanMinimum, { amount: MINIMUM_SELL_ADA.toString() }); - } else if (state.error === 'notEnoughBalance') { + } else if (state.inputError === 'notEnoughBalance') { helperText = intl.formatMessage(messages.notEnoughBalance); } @@ -301,7 +336,7 @@ export default class BuySellDialog extends Component { }} value={state.amountAda} onChange={this.onChangeAmount} - error={state.error !== null} + error={state.inputError !== null} helperText={helperText} autoFocus /> @@ -332,6 +367,34 @@ export default class BuySellDialog extends Component { const { intl } = this.context; const { state, props } = this; + if (this.state.urlGenerationError === 'longLoading') { + return ( + + ); + } + + if (this.state.urlGenerationError === 'timeout') { + const dismissUrlGenerationError = () => { + }; + + return ( + + ); + } + return ( { { label: intl.formatMessage(messages.proceed), primary: true, - disabled: state.amountAda === '' || state.error !== null, + disabled: state.amountAda === '' || state.inputError !== null, onClick: this.onSubmit, isSubmitting: state.isSubmitting, } diff --git a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js index 560c922c38..6dbf29775b 100644 --- a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js +++ b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js @@ -193,7 +193,7 @@ export default class NavBarContainerRevamp extends Component { () => this.props.actions.router.goToRoute.trigger({ route: ROUTES.EXCHANGE_END }) } currentBalanceAda={ - balance.getDefault().shiftedBy(-numberOfDecimals).toFormat(numberOfDecimals) + balance.getDefault().shiftedBy(-numberOfDecimals) } receiveAdaAddressPromise={getReceiveAdaAddress()} /> From fde6e29848e062d0d01223306af8e4bcd3f7b1ee Mon Sep 17 00:00:00 2001 From: yushi Date: Thu, 13 Jun 2024 17:22:51 +0800 Subject: [PATCH 05/16] url generation error handling --- .../images/service-unavailable-error.svg | 241 ++++++++++++++++++ .../app/components/buySell/BuySellDialog.js | 117 +++++++-- .../app/containers/NavBarContainerRevamp.js | 8 +- .../app/i18n/locales/en-US.json | 3 + 4 files changed, 339 insertions(+), 30 deletions(-) create mode 100644 packages/yoroi-extension/app/assets/images/service-unavailable-error.svg diff --git a/packages/yoroi-extension/app/assets/images/service-unavailable-error.svg b/packages/yoroi-extension/app/assets/images/service-unavailable-error.svg new file mode 100644 index 0000000000..ece9460022 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/service-unavailable-error.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index e3e32c9179..276ca95fa5 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -20,6 +20,8 @@ import adaPng from '../../assets/images/ada.png'; import banxaPng from '../../assets/images/banxa.png'; import encryptusPng from '../../assets/images/encryptus.png'; import { ReactComponent as InfoIcon } from '../../assets/images/info-icon-revamp.inline.svg'; +import { ReactComponent as YoroiIcon } from '../../assets/images/yoroi-logo-shape-blue.inline.svg'; +import { ReactComponent as FailIcon } from '../../assets/images/service-unavailable-error.svg'; import { exchangeApiMaker, exchangeManagerMaker } from '@yoroi/exchange' declare var chrome; @@ -55,12 +57,24 @@ const messages = defineMessages({ }, disclaimerText: { id: 'buysell.dialog.disclaimerText', - defaultMessage: '!!!Yoroi Wallet utilizes third-party web3 on-and-off ramp solutions for direct Fiat-ADA exchanges. By clicking "Proceed," you acknowledge that you will be redirected to our partner\'s website, where you may need to accept their terms and conditions. Please note, the third party web3 solution may have limitations based on your location and financial institution.' + defaultMessage: '!!!Yoroi Wallet utilizes third-party web3 on-and-off ramp solutions for direct Fiat-ADA exchanges. By clicking "Proceed," you acknowledge that you will be redirected to our partner\'s website, where you may need to accept their terms and conditions. Please note, the third party web3 solution may have limitations based on your location and financial institution.' }, proceed: { id: 'buysell.dialog.proceed', defaultMessage: 'PROCEED', }, + urlGenerationErrorDialogTitle: { + id: 'buysell.dialog.error.dialog.title', + defaultMessage: '!!!url generation', + }, + longLoadingDialogText: { + id: 'buysell.dialog.longloading.text', + defaultMessage: '!!!We are redirecting you outside Yoroi. Please wait.', + }, + failDialogText: { + id: 'buysell.dialog.fail.text', + defaultMessage: '!!!This service is currently unavailable. Please try again later.' + }, }); type Props = {| @@ -73,8 +87,8 @@ type Props = {| type State = {| +isBuying: boolean, +inputError: null | 'lessThanBuyMinimum' | 'notEnoughBalance' | 'lessThanSellMinimum', - // 'popOutDialog' is not really an error but is an temporary state - +urlGenenerationError: null | 'longLoading' | 'timeout' | 'fail', + // 'longLoading' is not really an error but is an temporary state + +urlGenerationError: null | 'longLoading' | 'timeout' | 'failed' | 'aborted', +amountAda: string, +isSubmitting: boolean, |}; @@ -153,6 +167,33 @@ const Disclaimer = styled(Box)({ padding: 'var(--spacing-12, 12px) var(--spacing-16, 16px) var(--spacing-16, 16px) var(--spacing-16, 16px)' }); +const ErrorPopoutContent = styled(Box)({ + height: '428px', + width: '343px', + // horizontally center the icon and text { + display: 'flex', + margin: 'auto', + '& .content': { + margin: 'auto', + }, + // } + '& svg': { + // vertically center { + display: 'block', + margin: '0 auto', + // } + width: '137px', + }, + '& .text': { + marginTop: '24px', + fontFamily: 'Rubik', + fontSize: '20px', + fontWeight: 500, + lineHeight: '30px', + textAlign: 'center', + }, +}); + const URL_GENERATION_LONG_LOADING_TIMEOUT = 2 * 1000; const URL_GENERATION_TIMEOUT = 30 * 1000; @@ -165,17 +206,17 @@ export default class BuySellDialog extends Component { state: State = { isBuying: true, inputError: null, - urlGenenerationError: null, + urlGenerationError: null, amountAda: '', isSubmitting: false, }; - urlGenerationTimeout: null | number = null; + urlGenerationTimeout: null | TimeoutID = null; onSubmit: () => Promise = async () => { const { state, props } = this; - this.setState({ isSubmitting: true }); + this.setState({ isSubmitting: true, urlGenerationError: null, }); const api = exchangeApiMaker({ isProduction: true, partner: 'yoroi' }); const manager = exchangeManagerMaker({ api }); @@ -210,10 +251,17 @@ export default class BuySellDialog extends Component { this.urlGenerationTimeout = setTimeout( () => { + // may already have failed + if (this.state.urlGenerationError) { + return; + } this.setState({ urlGenerationError: 'longLoading' }); this.urlGenerationTimeout = setTimeout( () => { - this.setState({ urlGenrationError: 'timeout' }); + if (this.state.urlGenerationError) { + return; + } + this.setState({ urlGenerationError: 'timeout' }); }, URL_GENERATION_TIMEOUT - URL_GENERATION_LONG_LOADING_TIMEOUT ); @@ -225,17 +273,19 @@ export default class BuySellDialog extends Component { try { url = await manager.referralLink.create(params); } catch { - this.setState({ urlGenerationError: 'fail' }); + this.setState({ urlGenerationError: 'failed' }); return; } finally { - cancelTimeout(this.urlGenerationTimeout); + clearTimeout(this.urlGenerationTimeout); } - // if timeout already happened, give up the process - if (this.state.urlGenerationError === 'timeout') { + // if timeout already happened or user aborted, give up on the process + const { urlGenerationError } = this.state; + if (urlGenerationError === 'timeout' || urlGenerationError === 'aborted') { return; } - this.setState({ urlGenrationError: null }); + // may be in `longLoading` now + this.setState({ urlGenerationError: null }); const self = this; chrome.tabs.create({ url: url.href }, (exchangePageTab) => { @@ -366,32 +416,49 @@ export default class BuySellDialog extends Component { render(): Node { const { intl } = this.context; const { state, props } = this; + const { urlGenerationError } = state; - if (this.state.urlGenerationError === 'longLoading') { + if (urlGenerationError === 'longLoading') { + const abortUrlGeneration = () => { + this.setState({ urlGenerationError: 'aborted', isSubmitting: false, }); + }; return ( + closeButton={} + onClose={abortUrlGeneration} + > + +
+ +
{intl.formatMessage(messages.longLoadingDialogText)}
+
+
+
); } - if (this.state.urlGenerationError === 'timeout') { + if (urlGenerationError === 'timeout' || urlGenerationError === 'failed') { const dismissUrlGenerationError = () => { + this.setState({ urlGenerationError: null }); }; return ( } onClose={dismissUrlGenerationError} - actions={[ - { - label: "ok", - onClick: dismissUrlGenerationError, - } - ]} - /> + closeOnOverlayClick={true} + > + +
+ +
{intl.formatMessage(messages.failDialogText)}
+
+
+
); } @@ -416,7 +483,7 @@ export default class BuySellDialog extends Component { > this.setState({ isBuying: !state.isBuying })} + onChange={() => this.setState({ isBuying: !state.isBuying, inputError: null, })} sx={{ width: '100%', [`& .${tabsClasses.indicator}`]: { diff --git a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js index 6dbf29775b..cc0dbf2d69 100644 --- a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js +++ b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js @@ -1,4 +1,5 @@ // @flow +import BigNumber from 'bignumber.js'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import type { Node } from 'react'; import type { StoresAndActionsProps } from '../types/injectedProps.types'; @@ -171,7 +172,7 @@ export default class NavBarContainerRevamp extends Component { } if (this.props.stores.uiDialogs.isOpen(BuySellDialog)) { - if (!publicDeriver || !balance) { + if (!publicDeriver) { return null; } const getReceiveAdaAddress = async () => { @@ -183,9 +184,6 @@ export default class NavBarContainerRevamp extends Component { ); }; - const tokenInfo = getTokenInfo(balance.getDefaultEntry()); - const { numberOfDecimals } = tokenInfo.Metadata; - return ( { () => this.props.actions.router.goToRoute.trigger({ route: ROUTES.EXCHANGE_END }) } currentBalanceAda={ - balance.getDefault().shiftedBy(-numberOfDecimals) + new BigNumber('1000') } receiveAdaAddressPromise={getReceiveAdaAddress()} /> diff --git a/packages/yoroi-extension/app/i18n/locales/en-US.json b/packages/yoroi-extension/app/i18n/locales/en-US.json index a711e96e41..089b098aa5 100644 --- a/packages/yoroi-extension/app/i18n/locales/en-US.json +++ b/packages/yoroi-extension/app/i18n/locales/en-US.json @@ -50,8 +50,11 @@ "buysell.dialog.currentBalance": "Current balance: {amount} ADA", "buysell.dialog.disclaimer": "Disclaimer", "buysell.dialog.disclaimerText": "Yoroi Wallet utilizes third-party web3 on-and-off ramp solutions for direct Fiat-ADA exchanges. By clicking \"Proceed,\" you acknowledge that you will be redirected to our partner's website, where you may need to accept their terms and conditions. Please note, the third party web3 solution may have limitations based on your location and financial institution.", + "buysell.dialog.error.dialog.title": "url generation", "buysell.dialog.error.minimum": "Minimum {amount} ADA required", "buysell.dialog.error.not.enough": "Not enough balance", + "buysell.dialog.fail.text": "This service is currently unavailable. Please try again later.", + "buysell.dialog.longloading.text": "We are redirecting you outside Yoroi. Please wait.", "buysell.dialog.proceed": "PROCEED", "buysell.dialog.provider": "Provider", "buysell.dialog.providerFee": "Provider fee", From 66422df2180c7ce08ea33cef239855a73e99bb1b Mon Sep 17 00:00:00 2001 From: yushi Date: Thu, 13 Jun 2024 17:34:41 +0800 Subject: [PATCH 06/16] fix --- .../app/components/buySell/BuySellDialog.js | 10 +++++----- packages/yoroi-extension/app/i18n/locales/en-US.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 276ca95fa5..6630215258 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -231,7 +231,7 @@ export default class BuySellDialog extends Component { orderType: 'buy', returnUrl: EXCHANGE_CALLBACK_URL, coinAmount: Number(state.amountAda), - balance: props.currentBalanceAda, + balance: props.currentBalanceAda.toString(), } } } else { @@ -244,7 +244,7 @@ export default class BuySellDialog extends Component { orderType: 'sell', returnUrl: EXCHANGE_CALLBACK_URL, coinAmount: Number(state.amountAda), - balance: props.currentBalanceAda, + balance: props.currentBalanceAda.toString(), } } } @@ -272,7 +272,7 @@ export default class BuySellDialog extends Component { let url; try { url = await manager.referralLink.create(params); - } catch { + } catch (_error) { this.setState({ urlGenerationError: 'failed' }); return; } finally { @@ -441,7 +441,7 @@ export default class BuySellDialog extends Component { if (urlGenerationError === 'timeout' || urlGenerationError === 'failed') { const dismissUrlGenerationError = () => { - this.setState({ urlGenerationError: null }); + this.setState({ urlGenerationError: null, isSubmitting: false, }); }; return ( @@ -464,7 +464,7 @@ export default class BuySellDialog extends Component { return ( } diff --git a/packages/yoroi-extension/app/i18n/locales/en-US.json b/packages/yoroi-extension/app/i18n/locales/en-US.json index 089b098aa5..4076cb8b46 100644 --- a/packages/yoroi-extension/app/i18n/locales/en-US.json +++ b/packages/yoroi-extension/app/i18n/locales/en-US.json @@ -953,7 +953,7 @@ "wallet.transaction.withdraw": "Withdraw", "wallet.transaction.withdrawalsLabel": "Withdrawals", "wallet.transactions.success.button.exchange": "Go to the exchange page", - "wallet.transactions.success.sell": "!!!Transaction has been submitted", + "wallet.transactions.success.sell": "Transaction has been submitted", "wallet.transfer.deregister.deregister": "Deregister", "wallet.transfer.deregister.keep": "Keep registered", "wallet.transfer.deregister.line1": "When withdrawing rewards, you also have the option to deregister the staking key", From 7af5c43a649ef4ee5e7ddeb1cb2fb902785beb4c Mon Sep 17 00:00:00 2001 From: yushi Date: Fri, 14 Jun 2024 01:13:07 +0800 Subject: [PATCH 07/16] revert unintended change --- .../app/containers/NavBarContainerRevamp.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js index cc0dbf2d69..6dbf29775b 100644 --- a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js +++ b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js @@ -1,5 +1,4 @@ // @flow -import BigNumber from 'bignumber.js'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import type { Node } from 'react'; import type { StoresAndActionsProps } from '../types/injectedProps.types'; @@ -172,7 +171,7 @@ export default class NavBarContainerRevamp extends Component { } if (this.props.stores.uiDialogs.isOpen(BuySellDialog)) { - if (!publicDeriver) { + if (!publicDeriver || !balance) { return null; } const getReceiveAdaAddress = async () => { @@ -184,6 +183,9 @@ export default class NavBarContainerRevamp extends Component { ); }; + const tokenInfo = getTokenInfo(balance.getDefaultEntry()); + const { numberOfDecimals } = tokenInfo.Metadata; + return ( { () => this.props.actions.router.goToRoute.trigger({ route: ROUTES.EXCHANGE_END }) } currentBalanceAda={ - new BigNumber('1000') + balance.getDefault().shiftedBy(-numberOfDecimals) } receiveAdaAddressPromise={getReceiveAdaAddress()} /> From 00dae4e332c1bc4ba86448c621d08200b3af557f Mon Sep 17 00:00:00 2001 From: yushi Date: Fri, 14 Jun 2024 11:46:27 +0800 Subject: [PATCH 08/16] round ada amount passed in --- packages/yoroi-extension/app/stores/toplevel/WalletStore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/stores/toplevel/WalletStore.js b/packages/yoroi-extension/app/stores/toplevel/WalletStore.js index 84780f4e3f..f17622e79e 100644 --- a/packages/yoroi-extension/app/stores/toplevel/WalletStore.js +++ b/packages/yoroi-extension/app/stores/toplevel/WalletStore.js @@ -32,7 +32,7 @@ import type { ActionsMap } from '../../actions/index'; import type { StoresMap } from '../index'; import { getWalletChecksum } from '../../api/export/utils'; import { MultiToken } from '../../api/common/lib/MultiToken'; -import { BigNumber } from 'bignumber.js'; +import { BigNumber, ROUND_UP } from 'bignumber.js'; type GroupedWallets = {| publicDerivers: Array>, @@ -360,7 +360,7 @@ export default class WalletStore extends Store { [{ identifier: defaultToken.defaultIdentifier, networkId: defaultToken.defaultNetworkId, - amount: (new BigNumber(sellAdaParams.amount)).shiftedBy(6), + amount: (new BigNumber(sellAdaParams.amount)).shiftedBy(6).decimalPlaces(0, ROUND_UP), }], defaultToken, ), From 52979604842ab33c2adcc07c4acd5a1dc6dbefa1 Mon Sep 17 00:00:00 2001 From: yushi Date: Fri, 14 Jun 2024 11:58:16 +0800 Subject: [PATCH 09/16] fix --- .../yoroi-extension/app/containers/NavBarContainerRevamp.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js index 8af59169cb..b7059ea580 100644 --- a/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js +++ b/packages/yoroi-extension/app/containers/NavBarContainerRevamp.js @@ -192,8 +192,8 @@ export default class NavBarContainerRevamp extends Component { return ( this.props.actions.router.goToRoute.trigger({ route: ROUTES.EXCHANGE_END }) + onExchangeCallback={() => + this.props.actions.router.goToRoute.trigger({ route: ROUTES.EXCHANGE_END }) } currentBalanceAda={ balance.getDefault().shiftedBy(-numberOfDecimals) From 7c397a8ba5454c695ae9186bb1ebd55c1e300061 Mon Sep 17 00:00:00 2001 From: yushi Date: Fri, 14 Jun 2024 12:02:30 +0800 Subject: [PATCH 10/16] flow fix --- packages/yoroi-extension/app/stores/toplevel/WalletStore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/stores/toplevel/WalletStore.js b/packages/yoroi-extension/app/stores/toplevel/WalletStore.js index f17622e79e..db55b53c71 100644 --- a/packages/yoroi-extension/app/stores/toplevel/WalletStore.js +++ b/packages/yoroi-extension/app/stores/toplevel/WalletStore.js @@ -32,7 +32,7 @@ import type { ActionsMap } from '../../actions/index'; import type { StoresMap } from '../index'; import { getWalletChecksum } from '../../api/export/utils'; import { MultiToken } from '../../api/common/lib/MultiToken'; -import { BigNumber, ROUND_UP } from 'bignumber.js'; +import { BigNumber } from 'bignumber.js'; type GroupedWallets = {| publicDerivers: Array>, @@ -360,7 +360,7 @@ export default class WalletStore extends Store { [{ identifier: defaultToken.defaultIdentifier, networkId: defaultToken.defaultNetworkId, - amount: (new BigNumber(sellAdaParams.amount)).shiftedBy(6).decimalPlaces(0, ROUND_UP), + amount: (new BigNumber(sellAdaParams.amount)).shiftedBy(6).decimalPlaces(0, 0/* ROUND_UP */), }], defaultToken, ), From 36185627feb08d0a4ea7362707f50583f31d486c Mon Sep 17 00:00:00 2001 From: yushi Date: Fri, 14 Jun 2024 12:22:05 +0800 Subject: [PATCH 11/16] lint --- .../app/components/buySell/BuySellDialog.js | 11 +++++------ .../app/stores/toplevel/LoadingStore.js | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 6630215258..100d4a3d48 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -430,9 +430,9 @@ export default class BuySellDialog extends Component { onClose={abortUrlGeneration} > -
+
-
{intl.formatMessage(messages.longLoadingDialogText)}
+
{intl.formatMessage(messages.longLoadingDialogText)}
@@ -447,15 +447,14 @@ export default class BuySellDialog extends Component { return ( } onClose={dismissUrlGenerationError} - closeOnOverlayClick={true} > -
+
-
{intl.formatMessage(messages.failDialogText)}
+
{intl.formatMessage(messages.failDialogText)}
diff --git a/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js b/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js index 1e870cbb12..ef2784a90b 100644 --- a/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js +++ b/packages/yoroi-extension/app/stores/toplevel/LoadingStore.js @@ -64,7 +64,7 @@ export default class LoadingStore extends BaseLoadingStore { this._uriParams = uriParams; }); From ed6c31f517bf5eb1e2f6b2250fcca12263cd2e55 Mon Sep 17 00:00:00 2001 From: yushi Date: Sat, 15 Jun 2024 01:19:14 +0800 Subject: [PATCH 12/16] lint --- .../yoroi-extension/app/components/buySell/BuySellDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 100d4a3d48..72eeb2a1f6 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -447,7 +447,7 @@ export default class BuySellDialog extends Component { return ( } onClose={dismissUrlGenerationError} > From af9d799c9da0d618e414ba3433989c4e3d2ab7ee Mon Sep 17 00:00:00 2001 From: yushi Date: Fri, 14 Jun 2024 08:54:00 +0800 Subject: [PATCH 13/16] disable selling ADA --- .../app/components/buySell/BuySellDialog.js | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 72eeb2a1f6..27595b6206 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -11,8 +11,6 @@ import DialogCloseButton from '../widgets/DialogCloseButton'; import globalMessages from '../../i18n/global-messages'; import { Box } from '@mui/material'; import { styled } from '@mui/material/styles'; -import Tab, { tabClasses } from '@mui/material/Tab'; -import Tabs, { tabsClasses } from '@mui/material/Tabs'; import TextField from '@mui/material/TextField'; import InputAdornment from '@mui/material/InputAdornment'; import BigNumber from 'bignumber.js'; @@ -97,24 +95,6 @@ const MINIMUM_BUY_ADA = new BigNumber('100'); const MINIMUM_SELL_ADA = new BigNumber('1'); const EXCHANGE_CALLBACK_URL = 'https://ramp-redirect.yoroiwallet.com/yoroi-extension-exchange-callback.html'; -const TabItem = styled(Tab)({ - position: 'relative', - borderRadius: '8px', - textAlign: 'center', - transition: 'all .5s', - padding: '10px 15px', - color: '#555555', - height: 'auto', - margin: '10px 0', - float: 'none', - fontSize: '12px', - fontWeight: '500', - [`&.${tabClasses.selected}, &.${tabClasses.root}:hover`]: { - color: '#555555', - backgroundColor: '#dce0e9', - }, -}); - const ProviderRow = styled(Box)({ display: 'flex', flexDirection: 'row', @@ -480,21 +460,6 @@ export default class BuySellDialog extends Component { styleOverride={{ width: '648px' }} styleFlags={{ contentNoTopPadding: true }} > - this.setState({ isBuying: !state.isBuying, inputError: null, })} - sx={{ - width: '100%', - [`& .${tabsClasses.indicator}`]: { - display: 'none', - }, - boxShadow: 'none', - }} - > - - - - {this.renderBuySell()} ); From b586114c58af1309c0d318aee1e67ecc40e3dfeb Mon Sep 17 00:00:00 2001 From: yushi Date: Sat, 15 Jun 2024 01:20:23 +0800 Subject: [PATCH 14/16] enable selling ADA for dev and nightly --- .../app/components/buySell/BuySellDialog.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 27595b6206..3502fa1e10 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -11,6 +11,8 @@ import DialogCloseButton from '../widgets/DialogCloseButton'; import globalMessages from '../../i18n/global-messages'; import { Box } from '@mui/material'; import { styled } from '@mui/material/styles'; +import Tab, { tabClasses } from '@mui/material/Tab'; +import Tabs, { tabsClasses } from '@mui/material/Tabs'; import TextField from '@mui/material/TextField'; import InputAdornment from '@mui/material/InputAdornment'; import BigNumber from 'bignumber.js'; @@ -21,6 +23,7 @@ import { ReactComponent as InfoIcon } from '../../assets/images/info-icon-revamp import { ReactComponent as YoroiIcon } from '../../assets/images/yoroi-logo-shape-blue.inline.svg'; import { ReactComponent as FailIcon } from '../../assets/images/service-unavailable-error.svg'; import { exchangeApiMaker, exchangeManagerMaker } from '@yoroi/exchange' +import environment from '../../environment'; declare var chrome; @@ -95,6 +98,24 @@ const MINIMUM_BUY_ADA = new BigNumber('100'); const MINIMUM_SELL_ADA = new BigNumber('1'); const EXCHANGE_CALLBACK_URL = 'https://ramp-redirect.yoroiwallet.com/yoroi-extension-exchange-callback.html'; +const TabItem = styled(Tab)({ + position: 'relative', + borderRadius: '8px', + textAlign: 'center', + transition: 'all .5s', + padding: '10px 15px', + color: '#555555', + height: 'auto', + margin: '10px 0', + float: 'none', + fontSize: '12px', + fontWeight: '500', + [`&.${tabClasses.selected}, &.${tabClasses.root}:hover`]: { + color: '#555555', + backgroundColor: '#dce0e9', + }, +}); + const ProviderRow = styled(Box)({ display: 'flex', flexDirection: 'row', @@ -460,6 +481,22 @@ export default class BuySellDialog extends Component { styleOverride={{ width: '648px' }} styleFlags={{ contentNoTopPadding: true }} > + {environment.isDev() && !environment.isNightly() && ( + this.setState({ isBuying: !state.isBuying })} + sx={{ + width: '100%', + [`& .${tabsClasses.indicator}`]: { + display: 'none', + }, + boxShadow: 'none', + }} + > + + + + )} {this.renderBuySell()}
); From 3cef417ffd46c0e719b2d82775fb344b1ae60b86 Mon Sep 17 00:00:00 2001 From: yushi Date: Sat, 15 Jun 2024 12:21:11 +0800 Subject: [PATCH 15/16] fix --- .../yoroi-extension/app/components/buySell/BuySellDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index 3502fa1e10..c48ad2ef19 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -484,7 +484,7 @@ export default class BuySellDialog extends Component { {environment.isDev() && !environment.isNightly() && ( this.setState({ isBuying: !state.isBuying })} + onChange={() => this.setState({ isBuying: !state.isBuying, inputError: null, })} sx={{ width: '100%', [`& .${tabsClasses.indicator}`]: { From b4e2906c99304402e17e8a3aac762d6159993100 Mon Sep 17 00:00:00 2001 From: yushi Date: Sat, 15 Jun 2024 12:38:12 +0800 Subject: [PATCH 16/16] fix button and dialog title text --- .../app/components/buySell/BuySellDialog.js | 8 ++++++-- .../app/components/topbar/BuySellAdaButton.js | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index c48ad2ef19..ec9ff2446b 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -198,6 +198,10 @@ const ErrorPopoutContent = styled(Box)({ const URL_GENERATION_LONG_LOADING_TIMEOUT = 2 * 1000; const URL_GENERATION_TIMEOUT = 30 * 1000; +const dialogTitle = (environment.isDev() || environment.isNightly()) ? + messages.dialogTitle : + globalMessages.buyAda; + @observer export default class BuySellDialog extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { @@ -464,7 +468,7 @@ export default class BuySellDialog extends Component { return ( } @@ -481,7 +485,7 @@ export default class BuySellDialog extends Component { styleOverride={{ width: '648px' }} styleFlags={{ contentNoTopPadding: true }} > - {environment.isDev() && !environment.isNightly() && ( + {environment.isDev() || environment.isNightly() && ( this.setState({ isBuying: !state.isBuying, inputError: null, })} diff --git a/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js b/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js index 726e07719d..c399c4eb33 100644 --- a/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js +++ b/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js @@ -8,6 +8,7 @@ import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import { intlShape } from 'react-intl'; import { withLayout } from '../../styles/context/layout'; import type { LayoutComponentMap } from '../../styles/context/layout'; +import environment from '../../environment'; type Props = {| +onBuySellClick: void => void, @@ -17,6 +18,10 @@ type InjectedProps = {| +renderLayoutComponent: LayoutComponentMap => Node, |}; +const buttonText = (environment.isDev() || environment.isNightly()) ? + globalMessages.buySellAda : + globalMessages.buyAda; + @observer class BuySellAdaButton extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { @@ -33,7 +38,7 @@ class BuySellAdaButton extends Component { className="secondary" onClick={() => this.props.onBuySellClick()} > - {intl.formatMessage(globalMessages.buyAda)} + {intl.formatMessage(buttonText)} ); @@ -46,7 +51,7 @@ class BuySellAdaButton extends Component { variant="secondary" onClick={() => this.props.onBuySellClick()} > - {intl.formatMessage(globalMessages.buySellAda)} + {intl.formatMessage(buttonText)} );