diff --git a/src/botPage/bot/TradeEngine/Balance.js b/src/botPage/bot/TradeEngine/Balance.js index 58ea161e25..8730573c2d 100644 --- a/src/botPage/bot/TradeEngine/Balance.js +++ b/src/botPage/bot/TradeEngine/Balance.js @@ -1,7 +1,6 @@ import { roundBalance } from '../../common/tools'; import { info } from '../broadcast'; - -let balanceStr = ''; +import { observer as globalObserver } from '../../../common/utils/observer'; export default Engine => class Balance extends Engine { @@ -11,8 +10,10 @@ export default Engine => balance: { balance: b, currency }, } = r; - this.balance = roundBalance({ currency, balance: b }); - balanceStr = `${this.balance} ${currency}`; + const balance = roundBalance({ currency, balance: b }); + const balanceStr = `${balance} ${currency}`; + + globalObserver.setState({ balance, currency }); info({ accountID: this.accountInfo.loginid, balance: balanceStr }); }); @@ -20,17 +21,19 @@ export default Engine => // eslint-disable-next-line class-methods-use-this getBalance(type) { const { scope } = this.store.getState(); - let { balance } = this; + const currency = globalObserver.getState('currency'); + let balance = globalObserver.getState('balance'); // Deduct trade `amount` in this scope for correct value in `balance`-block if (scope === 'BEFORE_PURCHASE') { balance = roundBalance({ - currency: this.tradeOptions.currency, - balance : Number(balance) - this.tradeOptions.amount, + balance: Number(balance) - this.tradeOptions.amount, + currency, }); - balanceStr = `${balance} ${this.tradeOptions.currency}`; } + const balanceStr = `${balance}`; + return type === 'STR' ? balanceStr : Number(balance); } }; diff --git a/src/botPage/bot/TradeEngine/index.js b/src/botPage/bot/TradeEngine/index.js index f93ffbd8ce..a9a2e03ea2 100644 --- a/src/botPage/bot/TradeEngine/index.js +++ b/src/botPage/bot/TradeEngine/index.js @@ -118,8 +118,15 @@ export default class TradeEngine extends Balance(Purchase(Sell(OpenContract(Prop // Only subscribe to balance in browser, not for tests. if (document) { - this.api.subscribeToBalance().then(r => { - this.balance = Number(r.balance.balance); + this.api.subscribeToBalance().then(response => { + const { + balance: { balance, currency }, + } = response; + + globalObserver.setState({ + balance: Number(balance), + currency, + }); resolve(); }); } else { diff --git a/src/botPage/bot/__tests__/BotApi.js b/src/botPage/bot/__tests__/BotApi.js index dab0901c31..c9bed14728 100644 --- a/src/botPage/bot/__tests__/BotApi.js +++ b/src/botPage/bot/__tests__/BotApi.js @@ -32,6 +32,7 @@ describe('Interface', () => { currency : 'USD', duration : 5, duration_unit: 't', + basis : 'stake', }); watch('before').then(c => { diff --git a/src/botPage/bot/__tests__/UI.js b/src/botPage/bot/__tests__/UI.js index d37f3bef43..91a62c8489 100644 --- a/src/botPage/bot/__tests__/UI.js +++ b/src/botPage/bot/__tests__/UI.js @@ -38,6 +38,7 @@ expectReturnTrue( prediction: undefined, barrierOffset: undefined, secondBarrierOffset: undefined, + basis: 'stake', }); } diff --git a/src/botPage/bot/__tests__/tools.js b/src/botPage/bot/__tests__/tools.js index 1999d2bdf9..9dd018c4bf 100644 --- a/src/botPage/bot/__tests__/tools.js +++ b/src/botPage/bot/__tests__/tools.js @@ -15,7 +15,8 @@ export const start = options => ` Bot.start({ amount: 1, - currency: 'USD', ${options || ''} + currency: 'USD', ${options || ''}, + basis: 'stake', }); `; diff --git a/src/botPage/bot/tools.js b/src/botPage/bot/tools.js index d4f535ec5b..2b509e9c58 100644 --- a/src/botPage/bot/tools.js +++ b/src/botPage/bot/tools.js @@ -9,7 +9,7 @@ export const tradeOptionToProposal = tradeOption => tradeOption.contractTypes.map(type => { const proposal = { duration_unit: tradeOption.duration_unit, - basis : 'stake', + basis : tradeOption.basis, currency : tradeOption.currency, symbol : tradeOption.symbol, duration : tradeOption.duration, diff --git a/src/botPage/common/const.js b/src/botPage/common/const.js index a35f5888bb..335b0a97da 100644 --- a/src/botPage/common/const.js +++ b/src/botPage/common/const.js @@ -8,10 +8,6 @@ const CRYPTO_CURRENCIES = ['BTC', 'ETH', 'LTC', 'BCH']; const config = { lists: { - PAYOUTTYPE: [ - // [translate('Payout'), 'payout'], - [translate('Stake'), 'stake'], - ], CRYPTO_CURRENCIES, DETAILS: [ [translate('statement'), '1'], @@ -232,9 +228,9 @@ const config = { bbResult : [[translate('upper'), '1'], [translate('middle'), '0'], [translate('lower'), '2']], macdFields: [[translate('Histogram'), '0'], [translate('MACD'), '1'], [translate('Signal'), '2']], gd : { - cid: '646610722767-7ivdbunktgtnumj23en9gkecbgtf2ur7.apps.googleusercontent.com', - aid: 'binarybot-237009', - api: 'AIzaSyBieTeLip_lVQZUimIuJypU1kJyqOvQRgc', + cid: '828416594271-qj2dnf4u2omg1iugangbtsrq6p0a55oc.apps.googleusercontent.com', + aid: 'derivbot-248506', + api: 'AIzaSyBDYQ7IIgGxM14IeAV5JrtaJNYjxB4A5jo', }, }; diff --git a/src/botPage/view/View.js b/src/botPage/view/View.js index b96e79b9d1..01fbc666f8 100644 --- a/src/botPage/view/View.js +++ b/src/botPage/view/View.js @@ -76,6 +76,8 @@ api.events.on('balance', response => { const element = elTopMenuBalance; element.textContent = `${balance} ${currency}`; }); + + globalObserver.setState({ balance: b, currency }); }); const addBalanceForToken = token => { diff --git a/src/botPage/view/blockly/blocks/trade/components.js b/src/botPage/view/blockly/blocks/trade/components.js index a11467343e..a99f248f9b 100644 --- a/src/botPage/view/blockly/blocks/trade/components.js +++ b/src/botPage/view/blockly/blocks/trade/components.js @@ -61,11 +61,17 @@ export const duration = block => { export const payout = block => { if (!block.getInput('AMOUNT')) { - block - .appendValueInput('AMOUNT') - .setCheck('Number') - .appendField(`${translate('Stake')}:`) - .appendField(new Blockly.FieldDropdown(config.lists.CURRENCY), 'CURRENCY_LIST'); + const amountInput = block.appendValueInput('AMOUNT'); + + amountInput.setCheck('Number'); + + if (block.type === 'tradeOptions_payout') { + amountInput.appendField(`${translate('Payout')}:`); + } else { + amountInput.appendField(`${translate('Stake')}:`); + } + + amountInput.appendField(new Blockly.FieldDropdown(config.lists.CURRENCY), 'CURRENCY_LIST'); } }; diff --git a/src/botPage/view/blockly/blocks/trade/tradeOptions.js b/src/botPage/view/blockly/blocks/trade/tradeOptions.js index 83581524c3..aa9b8c2a71 100644 --- a/src/botPage/view/blockly/blocks/trade/tradeOptions.js +++ b/src/botPage/view/blockly/blocks/trade/tradeOptions.js @@ -49,7 +49,7 @@ export default () => { if (!symbol) return; const getNestedTradeOptions = block => { - if (block.type === 'tradeOptions') { + if (/^tradeOptions/.test(block.type)) { this.pollForContracts(symbol).then(contracts => { this.updateBarrierOffsetBlocks(contracts, false, false, [block.id]); this.applyBarrierHandlebars('BARRIEROFFSETTYPE_LIST', [ev.blockId], true); @@ -141,7 +141,7 @@ export default () => { }); }, updatePredictionBlocks(contracts, updateOnly = []) { - getBlocksByType('tradeOptions').forEach(tradeOptionsBlock => { + getBlocksByType(this.type).forEach(tradeOptionsBlock => { if (tradeOptionsBlock.disabled) return; if (updateOnly.length && !updateOnly.includes(tradeOptionsBlock.id)) return; @@ -166,7 +166,7 @@ export default () => { }); }, updateBarrierOffsetBlocks(contracts, useDefaultType = false, setDefaultValue = false, updateOnly = []) { - getBlocksByType('tradeOptions').forEach(tradeOptionsBlock => { + getBlocksByType(this.type).forEach(tradeOptionsBlock => { if (tradeOptionsBlock.disabled) return; if (updateOnly.length && !updateOnly.includes(tradeOptionsBlock.id)) return; @@ -241,7 +241,7 @@ export default () => { }); }, updateDurationLists(contracts, useDefaultUnit = false, setMinDuration = false, updateOnly = []) { - getBlocksByType('tradeOptions').forEach(tradeOptionsBlock => { + getBlocksByType(this.type).forEach(tradeOptionsBlock => { if (tradeOptionsBlock.disabled) return; if (updateOnly.length && !updateOnly.includes(tradeOptionsBlock.id)) return; @@ -290,7 +290,7 @@ export default () => { }); }, applyBarrierHandlebars(barrierFieldName, forceDistinct = false, updateOnly = []) { - getBlocksByType('tradeOptions').forEach(tradeOptionsBlock => { + getBlocksByType(this.type).forEach(tradeOptionsBlock => { if (tradeOptionsBlock.disabled) return; if (updateOnly.length && !updateOnly.includes(tradeOptionsBlock.id)) return; @@ -318,6 +318,8 @@ export default () => { }); }, }; + Blockly.Blocks.tradeOptions_payout = Blockly.Blocks.tradeOptions; + Blockly.JavaScript.tradeOptions = block => { const durationValue = Blockly.JavaScript.valueToCode(block, 'DURATION', Blockly.JavaScript.ORDER_ATOMIC) || '0'; const durationType = block.getFieldValue('DURATIONTYPE_LIST'); @@ -366,8 +368,10 @@ export default () => { prediction: ${predictionValue}, barrierOffset: ${barrierOffsetValue}, secondBarrierOffset: ${secondBarrierOffsetValue}, + basis: '${block.type === 'tradeOptions_payout' ? 'payout' : 'stake'}', }); `; return code; }; + Blockly.JavaScript.tradeOptions_payout = Blockly.JavaScript.tradeOptions; }; diff --git a/src/common/integrations/GoogleDrive.js b/src/common/integrations/GoogleDrive.js index 1cdb4e61ee..9d748220a6 100644 --- a/src/common/integrations/GoogleDrive.js +++ b/src/common/integrations/GoogleDrive.js @@ -23,7 +23,7 @@ class GoogleDrive { .init({ apiKey : this.apiKey, clientId : this.clientId, - scope : 'https://www.googleapis.com/auth/drive.file', + scope : 'https://www.googleapis.com/auth/drive', discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'], }) .then( @@ -85,9 +85,7 @@ class GoogleDrive { if (response.error === 'access_denied') { globalObserver.emit( 'ui.log.warn', - translate( - 'Please grant permission to view and manage Google Drive folders created with Binary Bot' - ) + translate('Please grant permission to view and manage your Google Drive files') ); } reject(response); @@ -127,6 +125,7 @@ class GoogleDrive { const userPickedFile = data => { if (data.action === google.picker.Action.PICKED) { const fileId = data.docs[0].id; + gapi.client.drive.files .get({ alt : 'media', @@ -136,10 +135,10 @@ class GoogleDrive { .then(response => { try { const xmlDom = Blockly.Xml.textToDom(response.body); - const loadFunction = - xmlDom.hasAttribute('collection') && xmlDom.getAttribute('collection') === 'true' - ? loadBlocks - : loadWorkspace; + const isCollection = + xmlDom.hasAttribute('collection') && xmlDom.getAttribute('collection') === 'true'; + const loadFunction = isCollection ? loadBlocks : loadWorkspace; + try { loadFunction(xmlDom); resolve(); @@ -156,6 +155,7 @@ class GoogleDrive { if (error.status && error.status === 401) { this.signOut(); } + trackAndEmitError(translate('There was an error retrieving data from Google Drive'), error); reject(error); }); @@ -171,11 +171,9 @@ class GoogleDrive { gapi.client.drive.files .list() .then(() => { - const mimeTypes = ['application/xml']; const docsView = new google.picker.DocsView(); - docsView.setMimeTypes(mimeTypes.join(',')); docsView.setIncludeFolders(true); - docsView.setOwnedByMe(true); + docsView.setMimeTypes(['text/xml', 'application/xml']); const picker = new google.picker.PickerBuilder(); picker @@ -194,6 +192,7 @@ class GoogleDrive { if (error.status && error.status === 401) { this.signOut(); } + trackAndEmitError(translate('There was an error listing files from Google Drive'), error); reject(error); }); @@ -205,51 +204,40 @@ class GoogleDrive { getDefaultFolderId() { return new Promise((resolve, reject) => { // Avoid duplicate auth flow by checking if user is already authed - const authorisePromise = []; - if (!this.isAuthorised) { - authorisePromise.push(this.authorise); - } - Promise.all(authorisePromise) + Promise.all(!this.isAuthorised ? this.authorise : []) .then(() => { - gapi.client.drive.files - .list({ q: 'trashed=false' }) - // eslint-disable-next-line consistent-return - .then(response => { - const botFolder = response.result.files.find( - file => - file.name === this.botFolderName && - file.mimeType === 'application/vnd.google-apps.folder' - ); - if (botFolder) { - return resolve(botFolder.id); - } - gapi.client.drive.files - .create({ - resource: { - name : this.botFolderName, - mimeType: 'application/vnd.google-apps.folder', - fields : 'id', - }, - }) - .then(createFileResponse => resolve(createFileResponse.result.id)) - .catch(error => { - if (error.status && error.status === 401) { - this.signOut(); - } - trackAndEmitError( - translate('There was an error retrieving files from Google Drive'), - error - ); - reject(error); - }); - }) - .catch(error => { - if (error.status && error.status === 401) { - this.signOut(); - } - trackAndEmitError(translate('There was an error listing files from Google Drive'), error); - reject(error); - }); + // eslint-disable-next-line + gapi.client.drive.files.list({ q: 'trashed=false' }).then(response => { + const folder = response.result.files.find( + file => file.mimeType === 'application/vnd.google-apps.folder' + ); + + if (folder) { + return resolve(); + } + + gapi.client.drive.files + .create({ + resource: { + name : this.botFolderName, + mimeType: 'application/vnd.google-apps.folder', + fields : 'id', + }, + }) + .then(() => resolve()) + .catch(error => { + if (error.status && error.status === 401) { + this.signOut(); + } + + trackAndEmitError( + translate('There was an error retrieving files from Google Drive'), + error + ); + + reject(error); + }); + }); }) .catch(() => { /* Auth error, already handled in authorise()-promise */ @@ -285,6 +273,7 @@ class GoogleDrive { if (xhr.status === 401) { this.signOut(); } + trackAndEmitError(translate('There was an error processing your request'), xhr.status); reject(); } diff --git a/static/xml/toolbox.xml b/static/xml/toolbox.xml index 2dbce11e0b..56e5a54c00 100644 --- a/static/xml/toolbox.xml +++ b/static/xml/toolbox.xml @@ -259,6 +259,18 @@ + + + + 5 + + + + + 1 + + +