From c223de2c63117411ca697bec93c8270055415532 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Tue, 14 Feb 2017 19:50:15 -0300 Subject: [PATCH] Refactor Buy/Sell Glidera. Fix 2FA Code. Clean amount/confirm views --- src/js/controllers/amount.js | 25 +-- src/js/controllers/buyGlidera.js | 163 ++++++++++++++++ src/js/controllers/confirm.js | 228 +--------------------- src/js/controllers/glidera.js | 9 +- src/js/controllers/sellGlidera.js | 231 +++++++++++++++++++++++ src/js/routes.js | 19 +- src/js/services/glideraService.js | 48 +++-- src/sass/views/integrations/glidera.scss | 132 +++++++++++++ www/views/buyGlidera.html | 103 ++++++++++ www/views/confirm.html | 51 +---- www/views/glidera.html | 9 +- www/views/sellGlidera.html | 104 ++++++++++ 12 files changed, 802 insertions(+), 320 deletions(-) create mode 100644 src/js/controllers/buyGlidera.js create mode 100644 src/js/controllers/sellGlidera.js create mode 100644 www/views/buyGlidera.html create mode 100644 www/views/sellGlidera.html diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index 5e34d4c31..d7078a4ba 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, bitpayCardService, popupService, bwcError, payproService, profileService, bitcore, amazonService, glideraService) { +angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, bitpayCardService, popupService, bwcError, payproService, profileService, bitcore, amazonService) { var unitToSatoshi; var satToUnit; var unitDecimals; @@ -14,9 +14,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ }); $scope.$on("$ionicView.beforeEnter", function(event, data) { - // Glidera parameters - $scope.isGlidera = data.stateParams.isGlidera; - $scope.glideraAccessToken = data.stateParams.glideraAccessToken; // Go to... $scope.nextStep = data.stateParams.nextStep; @@ -30,26 +27,17 @@ angular.module('copayApp.controllers').controller('amountController', function($ $scope.toAddress = data.stateParams.toAddress; $scope.toName = data.stateParams.toName; $scope.toEmail = data.stateParams.toEmail; - $scope.showAlternativeAmount = !!$scope.cardId || !!$scope.isGlidera || !!$scope.nextStep; + $scope.showAlternativeAmount = !!$scope.cardId || !!$scope.nextStep; $scope.toColor = data.stateParams.toColor; $scope.showSendMax = false; $scope.customAmount = data.stateParams.customAmount; - if (!$scope.cardId && !$scope.isGlidera && !$scope.nextStep && !data.stateParams.toAddress) { + if (!$scope.cardId && !$scope.nextStep && !data.stateParams.toAddress) { $log.error('Bad params at amount') throw ('bad params'); } - if ($scope.isGlidera) { - glideraService.getLimits($scope.glideraAccessToken, function(err, limits) { - $scope.limits = limits; - $timeout(function() { - $scope.$apply(); - }); - }); - } - var reNr = /^[1234567890\.]$/; var reOp = /^[\*\+\-\/]$/; @@ -293,13 +281,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ }); }); - } else if ($scope.isGlidera) { - var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; - $state.transitionTo('tabs.buyandsell.glidera.confirm', { - toAmount: (amount * unitToSatoshi).toFixed(0), - isGlidera: $scope.isGlidera, - glideraAccessToken: $scope.glideraAccessToken - }); } else if ($scope.nextStep) { $state.transitionTo($scope.nextStep, { amount: _amount, diff --git a/src/js/controllers/buyGlidera.js b/src/js/controllers/buyGlidera.js new file mode 100644 index 000000000..475534806 --- /dev/null +++ b/src/js/controllers/buyGlidera.js @@ -0,0 +1,163 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('buyGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, glideraService, popupService, profileService, ongoingProcess, walletService) { + + var amount; + var currency; + + var showErrorAndBack = function(err) { + $scope.sendStatus = ''; + $log.error(err); + err = err.errors ? err.errors[0].message : err || ''; + popupService.showAlert('Error', err, function() { + $ionicHistory.goBack(); + }); + }; + + var showError = function(err) { + $scope.sendStatus = ''; + $log.error(err); + err = err.errors ? err.errors[0].message : err; + popupService.showAlert('Error', err); + }; + + var statusChangeHandler = function (processName, showName, isOn) { + $log.debug('statusChangeHandler: ', processName, showName, isOn); + if ( processName == 'buyingBitcoin' && !isOn) { + $scope.sendStatus = 'success'; + $timeout(function() { + $scope.$digest(); + }, 100); + } else if (showName) { + $scope.sendStatus = showName; + } + }; + + $scope.$on("$ionicView.beforeEnter", function(event, data) { + $scope.isFiat = data.stateParams.currency ? true : false; + var parsedAmount = glideraService.parseAmount( + data.stateParams.amount, + data.stateParams.currency); + + amount = parsedAmount.amount; + currency = parsedAmount.currency; + $scope.amountUnitStr = parsedAmount.amountUnitStr; + + $scope.network = glideraService.getNetwork(); + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: $scope.network + }); + $scope.wallet = $scope.wallets[0]; // Default first wallet + + ongoingProcess.set('connectingGlidera', true); + glideraService.init(function(err, data) { + if (err) { + ongoingProcess.set('connectingGlidera', false); + showErrorAndBack(err); + return; + } + $scope.token = data.token; + var price = {}; + if ($scope.isFiat) { + price['fiat'] = amount; + } else { + price['qty'] = amount; + } + glideraService.buyPrice($scope.token, price, function(err, buy) { + ongoingProcess.set('connectingGlidera', false); + if (err) { + showErrorAndBack(err); + return; + } + $scope.buyInfo = buy; + }); + }); + }); + + var ask2FaCode = function(mode, cb) { + if (mode != 'NONE') { + // SHOW PROMPT + var title = 'Please, enter the code below'; + var message; + if (mode == 'PIN') { + message = 'You have enabled PIN based two-factor authentication.'; + } else if (mode == 'AUTHENTICATOR') { + message = 'Use an authenticator app (Authy or Google Authenticator).'; + } else { + message = 'A SMS containing a confirmation code was sent to your phone.'; + } + popupService.showPrompt(title, message, null, function(twoFaCode) { + if (typeof twoFaCode == 'undefined') return cb(); + return cb(twoFaCode); + }); + } else { + return cb(); + } + }; + + $scope.buyConfirm = function() { + var message = 'Buy bitcoin for ' + amount + ' ' + currency; + var okText = 'Confirm'; + var cancelText = 'Cancel'; + popupService.showConfirm(null, message, okText, cancelText, function(ok) { + if (!ok) return; + ongoingProcess.set('buyingBitcoin', true, statusChangeHandler); + glideraService.get2faCode($scope.token, function(err, tfa) { + if (err) { + ongoingProcess.set('buyingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + ask2FaCode(tfa.mode, function(twoFaCode) { + if (tfa.mode != 'NONE' && lodash.isEmpty(twoFaCode)) { + ongoingProcess.set('buyingBitcoin', false, statusChangeHandler); + showError('No code entered'); + return; + } + + walletService.getAddress($scope.wallet, false, function(err, walletAddr) { + if (err) { + ongoingProcess.set('buyingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + var data = { + destinationAddress: walletAddr, + qty: $scope.buyInfo.qty, + priceUuid: $scope.buyInfo.priceUuid, + useCurrentPrice: false, + ip: null + }; + glideraService.buy($scope.token, twoFaCode, data, function(err, data) { + ongoingProcess.set('buyingBitcoin', false, statusChangeHandler); + if (err) return showError(err); + $log.info(data); + }); + }); + }); + }); + }); + }; + + $scope.showWalletSelector = function() { + $scope.walletSelectorTitle = 'Receive in'; + $scope.showWallets = true; + }; + + $scope.onWalletSelect = function(wallet) { + $scope.wallet = wallet; + }; + + $scope.goBackHome = function() { + $scope.sendStatus = ''; + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + $state.go('tabs.home').then(function() { + $state.transitionTo('tabs.buyandsell.glidera'); + }); + }; +}); diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index def38a854..64e54a6d7 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, glideraService, bwcError, bitpayCardService) { +angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError, bitpayCardService) { var cachedTxp = {}; var toAmount; var isChromeApp = platformInfo.isChromeApp; @@ -11,10 +11,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.$on("$ionicView.beforeEnter", function(event, data) { - // Glidera parameters - $scope.isGlidera = data.stateParams.isGlidera; - $scope.glideraAccessToken = data.stateParams.glideraAccessToken; - toAmount = data.stateParams.toAmount; cachedSendMax = {}; $scope.useSendMax = data.stateParams.useSendMax == 'true' ? true : false; @@ -39,8 +35,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( var config = configService.getSync().wallet; var feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal'; $scope.feeLevel = feeService.feeOpts[feeLevel]; - if ($scope.isGlidera) $scope.network = glideraService.getEnvironment(); - else $scope.network = (new bitcore.Address($scope.toAddress)).network.name; + $scope.network = (new bitcore.Address($scope.toAddress)).network.name; resetValues(); setwallets(); applyButtonText(); @@ -49,7 +44,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( function applyButtonText(multisig) { $scope.buttonText = $scope.isCordova ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' '; - if ($scope.isGlidera || $scope.cardId) { + if ($scope.cardId) { $scope.buttonText += gettextCatalog.getString('to complete'); } else if ($scope.paypro) { $scope.buttonText += gettextCatalog.getString('to pay'); @@ -75,11 +70,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( return; } - if ($scope.isGlidera == 'buy') { - initConfirm(); - return; - } - var filteredWallets = []; var index = 0; var enoughFunds = false; @@ -161,8 +151,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.alternativeAmountStr = v; }); } - if ($scope.isGlidera == 'buy') $scope.getBuyPrice(); - if ($scope.isGlidera == 'sell') $scope.getSellPrice(); }; function resetValues() { @@ -271,7 +259,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); $scope.showWalletSelector = function() { - $scope.walletSelectorTitle = $scope.isGlidera == 'buy' ? 'Receive in' : $scope.isGlidera == 'sell' ? 'Sell From' : gettextCatalog.getString('Send from'); + $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); if (!$scope.useSendMax && ($scope.insufficientFunds || $scope.noMatchingWallet)) return; $scope.showWallets = true; }; @@ -350,7 +338,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.wallet = wallet; $scope.fee = $scope.txp = null; - if ($scope.isGlidera) return; if (stop) { $timeout.cancel(stop); stop = null; @@ -476,47 +463,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( return; } - if ($scope.isGlidera) { - $scope.get2faCode(function(err, sent) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not send confirmation code to your phone')); - return; - } - if (sent) { - var title = gettextCatalog.getString("Please, enter the code below"); - var message = gettextCatalog.getString("A SMS containing a confirmation code was sent to your phone."); - popupService.showPrompt(title, message, null, function(twoFaCode) { - if (typeof twoFaCode == 'undefined') return; - if ($scope.isGlidera == 'buy') { - $scope.buyRequest(wallet, twoFaCode, function(err, data) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err); - return; - } - $scope.sendStatus = 'success'; - $timeout(function() { - $scope.$digest(); - }); - }) - } - if ($scope.isGlidera == 'sell') { - $scope.sellRequest(wallet, twoFaCode, function(err, data) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err); - return; - } - $scope.sendStatus = 'success'; - $timeout(function() { - $scope.$digest(); - }); - }) - } - }); - } - }); - return; - } - ongoingProcess.set('creatingTx', true, onSendStatusChange); createTx(wallet, false, function(err, txp) { ongoingProcess.set('creatingTx', false, onSendStatusChange); @@ -587,7 +533,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.onSuccessConfirm = function() { var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName; var fromBitPayCard = previousView.match(/tabs.bitpayCard/) ? true : false; - var fromGlidera = previousView.match(/tabs.buyandsell.glidera/) ? true : false; $ionicHistory.nextViewOptions({ disableAnimate: true @@ -601,15 +546,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( id: $stateParams.cardId }); }, 100); - } else if (fromGlidera) { - $ionicHistory.nextViewOptions({ - disableAnimate: true, - historyRoot: true - }); - $ionicHistory.clearHistory(); - $state.go('tabs.home').then(function() { - $state.transitionTo('tabs.buyandsell.glidera'); - }); } else { $ionicHistory.nextViewOptions({ disableAnimate: true, @@ -622,162 +558,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( } }; - $scope.get2faCode = function(cb) { - ongoingProcess.set('sending2faCode', true); - $timeout(function() { - glideraService.get2faCode($scope.glideraAccessToken, function(err, sent) { - ongoingProcess.set('sending2faCode', false); - return cb(err, sent); - }); - }, 100); - }; - - $scope.buyRequest = function(wallet, twoFaCode, cb) { - ongoingProcess.set('buyingBitcoin', true); - $timeout(function() { - walletService.getAddress(wallet, false, function(err, walletAddr) { - if (err) { - ongoingProcess.set('buyingBitcoin', false); - popupService.showAlert(gettextCatalog.getString('Error'), bwcError.cb(err, 'Could not create address')); - return; - } - var data = { - destinationAddress: walletAddr, - qty: $scope.buyPrice.qty, - priceUuid: $scope.buyPrice.priceUuid, - useCurrentPrice: false, - ip: null - }; - glideraService.buy($scope.glideraAccessToken, twoFaCode, data, function(err, data) { - ongoingProcess.set('buyingBitcoin', false); - return cb(err, data); - }); - }); - }, 100); - }; - - $scope.sellRequest = function(wallet, twoFaCode, cb) { - var outputs = []; - var config = configService.getSync(); - var configWallet = config.wallet; - var walletSettings = configWallet.settings; - - ongoingProcess.set('creatingTx', true); - walletService.getAddress(wallet, null, function(err, refundAddress) { - if (!refundAddress) { - ongoingProcess.clear(); - popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err, 'Could not create address')); - return; - } - glideraService.getSellAddress($scope.glideraAccessToken, function(err, sellAddress) { - if (!sellAddress || err) { - ongoingProcess.clear(); - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not get the destination bitcoin address')); - return; - } - var amount = parseInt(($scope.sellPrice.qty * 100000000).toFixed(0)); - var comment = 'Glidera transaction'; - - outputs.push({ - 'toAddress': sellAddress, - 'amount': amount, - 'message': comment - }); - - var txp = { - toAddress: sellAddress, - amount: amount, - outputs: outputs, - message: comment, - payProUrl: null, - excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, - feeLevel: walletSettings.feeLevel || 'normal', - customData: { - 'glideraToken': $scope.glideraAccessToken - } - }; - - walletService.createTx(wallet, txp, function(err, createdTxp) { - ongoingProcess.clear(); - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err.message || bwcError.msg(err)); - return; - } - walletService.prepare(wallet, function(err, password) { - if (err) { - ongoingProcess.clear(); - popupService.showAlert(gettextCatalog.getString('Error'), err.message || bwcError.msg(err)); - return; - } - ongoingProcess.set('signingTx', true); - walletService.publishTx(wallet, createdTxp, function(err, publishedTxp) { - if (err) { - ongoingProcess.clear(); - popupService.showAlert(gettextCatalog.getString('Error'), err.message ||  bwcError.msg(err)); - return; - } - - walletService.signTx(wallet, publishedTxp, password, function(err, signedTxp) { - if (err) { - ongoingProcess.clear(); - popupService.showAlert(gettextCatalog.getString('Error'), err.message ||  bwcError.msg(err)); - walletService.removeTx(wallet, signedTxp, function(err) { - if (err) $log.debug(err); - }); - return; - } - var rawTx = signedTxp.raw; - var data = { - refundAddress: refundAddress, - signedTransaction: rawTx, - priceUuid: $scope.sellPrice.priceUuid, - useCurrentPrice: $scope.sellPrice.priceUuid ? false : true, - ip: null - }; - ongoingProcess.set('sellingBitcoin', true); - glideraService.sell($scope.glideraAccessToken, twoFaCode, data, function(err, data) { - ongoingProcess.clear(); - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err.message ||  bwcError.msg(err)); - return; - } - return cb(err, data) - }); - }); - }); - }); - }); - }); - }); - } - - $scope.getBuyPrice = function() { - var satToBtc = 1 / 100000000; - var price = {}; - price.qty = (toAmount * satToBtc).toFixed(8); - glideraService.buyPrice($scope.glideraAccessToken, price, function(err, buyPrice) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), 'Could not get exchange information. Please, try again'); - return; - } - $scope.buyPrice = buyPrice; - }); - }; - - $scope.getSellPrice = function() { - var satToBtc = 1 / 100000000; - var price = {}; - price.qty = (toAmount * satToBtc).toFixed(8); - - glideraService.sellPrice($scope.glideraAccessToken, price, function(err, sellPrice) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), 'Could not get exchange information. Please, try again'); - return; - } - $scope.sellPrice = sellPrice; - }); - }; - function publishAndSign(wallet, txp, onSendStatusChange) { if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { diff --git a/src/js/controllers/glidera.js b/src/js/controllers/glidera.js index 5c55fe3f1..de903d15b 100644 --- a/src/js/controllers/glidera.js +++ b/src/js/controllers/glidera.js @@ -92,20 +92,13 @@ angular.module('copayApp.controllers').controller('glideraController', externalLinkService.open(url, optIn, title, message, okText, cancelText); } - $scope.retry = function() { - $scope.connectingGlidera = true; - $scope.update({'fullUpdate': true}); - $timeout(function(){ - $scope.connectingGlidera = false; - }, 300); - } - $scope.toggleOauthForm = function() { $scope.showOauthForm = !$scope.showOauthForm; } $scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.network = glideraService.getNetwork(); + $scope.currency = glideraService.getCurrency(); $scope.showOauthForm = false; $scope.account = {}; if (data.stateParams && data.stateParams.code) { diff --git a/src/js/controllers/sellGlidera.js b/src/js/controllers/sellGlidera.js new file mode 100644 index 000000000..c99c2f478 --- /dev/null +++ b/src/js/controllers/sellGlidera.js @@ -0,0 +1,231 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('sellGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, configService) { + + var amount; + var currency; + + var showErrorAndBack = function(err) { + $scope.sendStatus = ''; + $log.error(err); + err = err.errors ? err.errors[0].message : err; + popupService.showAlert('Error', err, function() { + $ionicHistory.goBack(); + }); + }; + + var showError = function(err) { + $scope.sendStatus = ''; + $log.error(err); + err = err.errors ? err.errors[0].message : err; + popupService.showAlert('Error', err); + }; + + var statusChangeHandler = function (processName, showName, isOn) { + $log.debug('statusChangeHandler: ', processName, showName, isOn); + if ( processName == 'sellingBitcoin' && !isOn) { + $scope.sendStatus = 'success'; + $timeout(function() { + $scope.$digest(); + }, 100); + } else if (showName) { + $scope.sendStatus = showName; + } + }; + + $scope.$on("$ionicView.beforeEnter", function(event, data) { + $scope.isFiat = data.stateParams.currency ? true : false; + var parsedAmount = glideraService.parseAmount( + data.stateParams.amount, + data.stateParams.currency); + + amount = parsedAmount.amount; + currency = parsedAmount.currency; + $scope.amountUnitStr = parsedAmount.amountUnitStr; + + $scope.network = glideraService.getNetwork(); + $scope.wallets = profileService.getWallets({ + m: 1, // Only 1-signature wallet + onlyComplete: true, + network: $scope.network + }); + $scope.wallet = $scope.wallets[0]; // Default first wallet + + ongoingProcess.set('connectingGlidera', true); + glideraService.init(function(err, data) { + if (err) { + ongoingProcess.set('connectingGlidera', false); + showErrorAndBack(err); + return; + } + $scope.token = data.token; + var price = {}; + if ($scope.isFiat) { + price['fiat'] = amount; + } else { + price['qty'] = amount; + } + glideraService.sellPrice($scope.token, price, function(err, sell) { + ongoingProcess.set('connectingGlidera', false); + if (err) { + showErrorAndBack(err); + return; + } + $scope.sellInfo = sell; + }); + }); + }); + + var ask2FaCode = function(mode, cb) { + if (mode != 'NONE') { + // SHOW PROMPT + var title = 'Please, enter the code below'; + var message; + if (mode == 'PIN') { + message = 'You have enabled PIN based two-factor authentication.'; + } else if (mode == 'AUTHENTICATOR') { + message = 'Use an authenticator app (Authy or Google Authenticator).'; + } else { + message = 'A SMS containing a confirmation code was sent to your phone.'; + } + popupService.showPrompt(title, message, null, function(twoFaCode) { + if (typeof twoFaCode == 'undefined') return cb(); + return cb(twoFaCode); + }); + } else { + return cb(); + } + }; + + $scope.sellConfirm = function() { + var message = 'Sell bitcoin for ' + amount + ' ' + currency; + var okText = 'Confirm'; + var cancelText = 'Cancel'; + popupService.showConfirm(null, message, okText, cancelText, function(ok) { + if (!ok) return; + ongoingProcess.set('sellingBitcoin', true, statusChangeHandler); + glideraService.get2faCode($scope.token, function(err, tfa) { + if (err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + ask2FaCode(tfa.mode, function(twoFaCode) { + if (tfa.mode != 'NONE' && lodash.isEmpty(twoFaCode)) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError('No code entered'); + return; + } + + var outputs = []; + var config = configService.getSync(); + var configWallet = config.wallet; + var walletSettings = configWallet.settings; + + walletService.getAddress($scope.wallet, null, function(err, refundAddress) { + if (!refundAddress) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError('Could not create address'); + return; + } + glideraService.getSellAddress($scope.token, function(err, sellAddress) { + if (!sellAddress || err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + var amount = parseInt(($scope.sellInfo.qty * 100000000).toFixed(0)); + var comment = 'Glidera transaction'; + + outputs.push({ + 'toAddress': sellAddress, + 'amount': amount, + 'message': comment + }); + + var txp = { + toAddress: sellAddress, + amount: amount, + outputs: outputs, + message: comment, + payProUrl: null, + excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, + feeLevel: walletSettings.feeLevel || 'normal', + customData: { + 'glideraToken': $scope.token + } + }; + + walletService.createTx($scope.wallet, txp, function(err, createdTxp) { + if (err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + walletService.prepare($scope.wallet, function(err, password) { + if (err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + walletService.publishTx($scope.wallet, createdTxp, function(err, publishedTxp) { + if (err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError(err); + return; + } + walletService.signTx($scope.wallet, publishedTxp, password, function(err, signedTxp) { + if (err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError(err); + walletService.removeTx($scope.wallet, signedTxp, function(err) { + if (err) $log.debug(err); + }); + return; + } + var rawTx = signedTxp.raw; + var data = { + refundAddress: refundAddress, + signedTransaction: rawTx, + priceUuid: $scope.sellInfo.priceUuid, + useCurrentPrice: $scope.sellInfo.priceUuid ? false : true, + ip: null + }; + glideraService.sell($scope.token, twoFaCode, data, function(err, data) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + if (err) return showError(err); + $log.info(data); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }; + + $scope.showWalletSelector = function() { + $scope.walletSelectorTitle = 'Sell From'; + $scope.showWallets = true; + }; + + $scope.onWalletSelect = function(wallet) { + $scope.wallet = wallet; + }; + + $scope.goBackHome = function() { + $scope.sendStatus = ''; + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + $state.go('tabs.home').then(function() { + $state.transitionTo('tabs.buyandsell.glidera'); + }); + }; + +}); diff --git a/src/js/routes.js b/src/js/routes.js index 81354ded8..d3a8e557b 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -885,7 +885,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.buyandsell.glidera.amount', { - url: '/amount/:isGlidera/:glideraAccessToken', + url: '/amount/:nextStep/:currency', views: { 'tab-home@tabs': { controller: 'amountController', @@ -893,12 +893,21 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } } }) - .state('tabs.buyandsell.glidera.confirm', { - url: '/confirm/:toAmount/:isGlidera/:glideraAccessToken', + .state('tabs.buyandsell.glidera.buy', { + url: '/buy/:amount/:currency', views: { 'tab-home@tabs': { - controller: 'confirmController', - templateUrl: 'views/confirm.html' + controller: 'buyGlideraController', + templateUrl: 'views/buyGlidera.html' + } + } + }) + .state('tabs.buyandsell.glidera.sell', { + url: '/sell/:amount/:currency', + views: { + 'tab-home@tabs': { + controller: 'sellGlideraController', + templateUrl: 'views/sellGlidera.html' } } }) diff --git a/src/js/services/glideraService.js b/src/js/services/glideraService.js index 08d227733..0fd2e1b0a 100644 --- a/src/js/services/glideraService.js +++ b/src/js/services/glideraService.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.services').factory('glideraService', function($http, $log, $window, platformInfo, storageService, buyAndSellService, lodash) { +angular.module('copayApp.services').factory('glideraService', function($http, $log, $window, $filter, platformInfo, storageService, buyAndSellService, lodash, configService, txFormatService) { var root = {}; var credentials = {}; var isCordova = platformInfo.isCordova; @@ -49,6 +49,34 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l return credentials.NETWORK; }; + root.getCurrency = function() { + return 'USD'; + }; + + root.parseAmount = function(amount, currency) { + var config = configService.getSync().wallet.settings; + var satToBtc = 1 / 100000000; + var unitToSatoshi = config.unitToSatoshi; + var amountUnitStr; + + // IF 'USD' + if (currency) { + amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency; + } else { + var amountSat = parseInt((amount * unitToSatoshi).toFixed(0)); + amountUnitStr = txFormatService.formatAmountStr(amountSat); + // convert unit to BTC + amount = (amountSat * satToBtc).toFixed(8); + currency = 'BTC'; + } + + return { + amount: amount, + currency: currency, + amountUnitStr: amountUnitStr + }; + }; + root.getSignupUrl = function() { return credentials.HOST + '/register'; } @@ -225,18 +253,13 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l }; root.get2faCode = function(token, cb) { - if (!token) { - $log.error('Glidera Sent 2FA code by SMS: ERROR Invalid Token'); - return cb('Invalid Token'); - } - + if (!token) return cb('Invalid Token'); $http(_get('/authentication/get2faCode', token)).then(function(data) { - - $log.info('Glidera Sent 2FA code by SMS: SUCCESS'); - return cb(null, data.status == 200 ? true : false); + $log.info('Glidera 2FA code: SUCCESS'); + return cb(null, data.data); }, function(data) { - $log.error('Glidera Sent 2FA code by SMS: ERROR ' + data.statusText); - return cb('Glidera Sent 2FA code by SMS: ERROR ' + data.statusText); + $log.error('Glidera 2FA code: ERROR ' + data.statusText); + return cb('Glidera 2FA code: ERROR ' + data.statusText); }); }; @@ -248,7 +271,7 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer ' + token, - '2FA_CODE': twoFaCode + 'X-2FA-CODE': twoFaCode }, data: data }; @@ -308,6 +331,7 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l ip: data.ip }; $http(_post('/buy', token, twoFaCode, data)).then(function(data) { +console.log('[glideraService.js:333]',data); //TODO $log.info('Glidera Buy: SUCCESS'); return cb(null, data.data); }, function(data) { diff --git a/src/sass/views/integrations/glidera.scss b/src/sass/views/integrations/glidera.scss index fea75b498..0dd003c3a 100644 --- a/src/sass/views/integrations/glidera.scss +++ b/src/sass/views/integrations/glidera.scss @@ -1,4 +1,136 @@ #glidera { + $item-lateral-padding: 20px; + $item-vertical-padding: 10px; + $item-border-color: #EFEFEF; + $item-label-color: #6C6C6E; + @extend .deflash-blue; + + .spinner svg { + stroke: #0067c8; + fill: #0067c8; + } + + .add-bottom-for-cta { + bottom: 92px; + } + .head { + padding: 30px $item-lateral-padding 4rem; + border-top: 0; + + .sending-label { + display: flex; + font-size: 18px; + align-items: center; + margin-bottom: 1.5rem; + + img { + margin-right: 1rem; + height: 35px; + width: 35px; + } + + span { + text-transform: capitalize; + } + } + .amount-label{ + line-height: 30px; + .amount{ + font-size: 38px; + margin-bottom: .5rem; + + > .unit { + font-family: "Roboto-Light"; + } + } + .alternative { + font-size: 16px; + font-family: "Roboto-Light"; + color: #9B9B9B; + } + } + } + .item { + border-color: $item-border-color; + } + .info { + .badge { + border-radius: 0; + padding: .5rem; + } + .item { + color: #4A4A4A; + padding-top: $item-vertical-padding; + padding-bottom: $item-vertical-padding; + padding-left: $item-lateral-padding; + + &:not(.item-icon-right) { + padding-right: $item-lateral-padding; + } + + .label { + font-size: 14px; + color: $item-label-color; + margin-bottom: 8px; + } + + .capitalized { + text-transform: capitalize; + } + + .wallet .big-icon-svg > .bg { + height: 24px; + width: 24px; + padding: 2px; + box-shadow: none; + vertical-align: middle; + } + + .total-amount { + font-weight: bold; + } + + &.single-line { + display: flex; + align-items: center; + padding-top: 17px; + padding-bottom: 17px; + + .label { + margin: 0; + flex-grow: 1; + } + } + } + .item-divider { + padding-top: 1.2rem; + color: $item-label-color; + font-size: 15px; + } + .wallet { + display: flex; + align-items: center; + padding: .2rem 0; + margin-bottom: 5px; + + ~ .bp-arrow-right { + top: 14px; + } + + > i { + padding: 0; + position: static; + + > img { + height: 24px; + width: 24px; + padding: 2px; + margin-right: .7rem; + box-shadow: none; + } + } + } + } .glidera-lead { margin: 2rem 1rem; color: $dark-gray; diff --git a/www/views/buyGlidera.html b/www/views/buyGlidera.html new file mode 100644 index 000000000..6f33c08af --- /dev/null +++ b/www/views/buyGlidera.html @@ -0,0 +1,103 @@ + + + + + Buy bitcoin + + + + +
+ +
+
+ buy bitcoin + Buying +
+
+
{{amountUnitStr}}
+
+ {{buyInfo.subtotal}} {{buyInfo.currency}} + {{buyInfo.qty}} BTC + @ ${{buyInfo.price}} per BTC +
+
+
+ +
+ +
+
Receive in
+
+ + + + {{wallet ? wallet.name : '...'}} +
+ +
+ +
+ Transaction details +
+
+ Expires + + {{buyInfo.expires | amCalendar}} + +
+
+ Fees + + {{buyInfo.fees}} {{buyInfo.currency}} + +
+
+ Total to pay + + {{buyInfo.total}} {{buyInfo.currency}} + +
+
+
+ +
+ + + Confirm purchase + + + Slide to buy + + + Bought +
+ A transfer has been initiated from your bank account. Your bitcoins should arrive to your wallet in 2-4 business day +
+
+ + + +
diff --git a/www/views/confirm.html b/www/views/confirm.html index 54d56c87b..c1a22bb03 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -12,10 +12,8 @@
- Sending + Sending Sending maximum amount - Buying - Selling
{{displayAmount || '...'}} {{displayUnit}}
@@ -31,16 +29,13 @@
- To - From - To + To - +
-
@@ -58,9 +53,7 @@
- From - To - From + From
@@ -75,47 +68,19 @@
- + Add Memo {{description}} -
+
{{'Fee' | translate}}: {{feeLevel | translate}} {{fee || '...'}}
-
- Information -
-
- Buy {{buyPrice.subtotal|currency:'':2}} {{buyPrice.currency}} in Bitcoin at {{buyPrice.price}} {{buyPrice.currency}}/BTC -
-
- Fiat will be immediately withdrawn from your bank account. -
-
- The bitcoins will be purchased and deposited to "{{wallet.name || '...' }}" wallet in 2-4 business days. -
-
-
-
- Information -
-
- Sell {{sellPrice.subtotal|currency:'':2}} {{sellPrice.currency}} in Bitcoin at {{sellPrice.price|currency:'':2}} {{sellPrice.currency}}/BTC -
-
- Fiat will be deposited in your bank account in 4-6 business days. -
-
- Bitcoins will be immediately sent from your "{{wallet.name || '...' }}" wallet to Glidera. -
-
-
No wallets available
@@ -150,10 +115,6 @@ Payment Sent Proposal Created Transaction created -
- A transfer has been initiated from your bank account. Your bitcoins should arrive to your wallet in 2-4 business day - A transfer has been initiated to your bank account. Should arrive in 4-6 business days -
Enter Code Restart - @@ -58,13 +59,13 @@
- +