diff --git a/src/js/controllers/amazon.js b/src/js/controllers/amazon.js index df1c8b666..2707a25e3 100644 --- a/src/js/controllers/amazon.js +++ b/src/js/controllers/amazon.js @@ -1,9 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('amazonController', - function($scope, $timeout, $ionicModal, $log, $ionicScrollDelegate, lodash, amazonService, platformInfo, externalLinkService, popupService, ongoingProcess) { - - $scope.network = amazonService.getEnvironment(); + function($scope, $timeout, $ionicModal, $log, $state, $ionicHistory, lodash, amazonService, externalLinkService, popupService) { $scope.openExternalLink = function(url) { externalLinkService.open(url); @@ -11,108 +9,16 @@ angular.module('copayApp.controllers').controller('amazonController', var initAmazon = function() { amazonService.getPendingGiftCards(function(err, gcds) { - if (err) { - popupService.showAlert('Error', err); - return; - } - $scope.giftCards = lodash.isEmpty(gcds) ? null : gcds; + if (err) $log.error(err); + $scope.giftCards = gcds; $timeout(function() { $scope.$digest(); }); - if ($scope.cardClaimCode) { - var card = lodash.find($scope.giftCards, { - claimCode: $scope.cardClaimCode - }); - if (lodash.isEmpty(card)) { - popupService.showAlert('Error', 'Card not found'); - return; - } - $scope.openCardModal(card); - } - }); - $scope.updatePendingGiftCards(); - }; - - $scope.updatePendingGiftCards = lodash.debounce(function() { - ongoingProcess.set('updatingGiftCards', true); - amazonService.getPendingGiftCards(function(err, gcds) { - if (lodash.isEmpty(gcds)) { - $timeout(function() { - ongoingProcess.set('updatingGiftCards', false); - }, 1000); - } - $timeout(function() { - $scope.giftCards = lodash.isEmpty(gcds) ? null : gcds; - $scope.$digest(); - }); - var index = 0; - lodash.forEach(gcds, function(dataFromStorage) { - if (++index == Object.keys(gcds).length) { - $timeout(function() { - ongoingProcess.set('updatingGiftCards', false); - }, 1000); - } - if (dataFromStorage.status == 'PENDING') { - $log.debug("creating gift card"); - amazonService.createGiftCard(dataFromStorage, function(err, giftCard) { - if (err) { - popupService.showAlert('Error', err); - return; - } - if (giftCard.status != 'PENDING') { - var newData = {}; - - lodash.merge(newData, dataFromStorage, giftCard); - - if (newData.status == 'expired') { - amazonService.savePendingGiftCard(newData, { - remove: true - }, function(err) { - return; - }); - } - - amazonService.savePendingGiftCard(newData, null, function(err) { - $log.debug("Saving new gift card"); - amazonService.getPendingGiftCards(function(err, gcds) { - if (err) { - popupService.showAlert('Error', err); - return; - } - $scope.giftCards = lodash.isEmpty(gcds) ? null : gcds; - $timeout(function() { - $scope.$digest(); - $ionicScrollDelegate.resize(); - }, 10); - }); - }); - } else $log.debug("pending gift card not available yet"); - }); - } - }); - }); - - }, 1000, { - 'leading': true - }); - - $scope.openCardModal = function(card) { - $scope.card = card; - - $ionicModal.fromTemplateUrl('views/modals/amazon-card-details.html', { - scope: $scope - }).then(function(modal) { - $scope.amazonCardDetailsModal = modal; - $scope.amazonCardDetailsModal.show(); - }); - - $scope.$on('modal.hidden', function() { - $scope.updatePendingGiftCards(); }); }; $scope.$on("$ionicView.beforeEnter", function(event, data) { - $scope.cardClaimCode = data.stateParams.cardClaimCode; + $scope.network = amazonService.getNetwork(); initAmazon(); }); }); diff --git a/src/js/controllers/amazonCards.js b/src/js/controllers/amazonCards.js new file mode 100644 index 000000000..329c620fc --- /dev/null +++ b/src/js/controllers/amazonCards.js @@ -0,0 +1,103 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('amazonCardsController', + function($scope, $timeout, $ionicModal, $log, $ionicScrollDelegate, lodash, amazonService, platformInfo, externalLinkService, popupService, ongoingProcess) { + + $scope.openExternalLink = function(url) { + externalLinkService.open(url); + }; + + var updateGiftCards = function(cb) { + amazonService.getPendingGiftCards(function(err, gcds) { + if (err) { + popupService.showAlert('Could not get gift cards', err); + if (cb) return cb(); + else return; + } + $scope.giftCards = gcds; + $timeout(function() { + $scope.$digest(); + $ionicScrollDelegate.resize(); + if (cb) return cb(); + }, 100); + }); + }; + + $scope.updatePendingGiftCards = lodash.debounce(function() { + $scope.updatingPending = {}; + updateGiftCards(function() { + var index = 0; + var gcds = $scope.giftCards; + lodash.forEach(gcds, function(dataFromStorage) { + if (dataFromStorage.status == 'PENDING') { + $log.debug("creating gift card"); + $scope.updatingPending[dataFromStorage.invoiceId] = true; + amazonService.createGiftCard(dataFromStorage, function(err, giftCard) { + $scope.updatingPending[dataFromStorage.invoiceId] = false; + if (err) { + popupService.showAlert('Error creating gift card', err); + return; + } + if (giftCard.status != 'PENDING') { + var newData = {}; + + lodash.merge(newData, dataFromStorage, giftCard); + + if (newData.status == 'expired') { + amazonService.savePendingGiftCard(newData, { + remove: true + }, function(err) { + updateGiftCards(); + return; + }); + } + + amazonService.savePendingGiftCard(newData, null, function(err) { + $log.debug("Saving new gift card"); + updateGiftCards(); + }); + } + }); + } + }); + }); + + }, 1000, { + 'leading': true + }); + + $scope.openCardModal = function(card) { + $scope.card = card; + + $ionicModal.fromTemplateUrl('views/modals/amazon-card-details.html', { + scope: $scope + }).then(function(modal) { + $scope.amazonCardDetailsModal = modal; + $scope.amazonCardDetailsModal.show(); + }); + + $scope.$on('modal.hidden', function() { + $scope.updatePendingGiftCards(); + }); + }; + + $scope.$on("$ionicView.beforeEnter", function(event, data) { + $scope.cardClaimCode = data.stateParams.cardClaimCode; + updateGiftCards(function() { + if ($scope.cardClaimCode) { + var card = lodash.find($scope.giftCards, { + claimCode: $scope.cardClaimCode + }); + if (lodash.isEmpty(card)) { + popupService.showAlert(null, 'Card not found'); + return; + } + $scope.openCardModal(card); + } + }); + }); + + $scope.$on("$ionicView.afterEnter", function(event, data) { + $scope.updatePendingGiftCards(); + }); + }); diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index 259c4930b..5e34d4c31 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -14,14 +14,14 @@ angular.module('copayApp.controllers').controller('amountController', function($ }); $scope.$on("$ionicView.beforeEnter", function(event, data) { - $scope.isGiftCard = data.stateParams.isGiftCard; - // Glidera parameters $scope.isGlidera = data.stateParams.isGlidera; $scope.glideraAccessToken = data.stateParams.glideraAccessToken; // Go to... $scope.nextStep = data.stateParams.nextStep; + $scope.currency = data.stateParams.currency; + $scope.forceCurrency = data.stateParams.forceCurrency; $scope.cardId = data.stateParams.cardId; $scope.showMenu = $ionicHistory.backView() && $ionicHistory.backView().stateName == 'tabs.send'; @@ -30,13 +30,13 @@ 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.isGiftCard || !!$scope.isGlidera || !!$scope.nextStep; + $scope.showAlternativeAmount = !!$scope.cardId || !!$scope.isGlidera || !!$scope.nextStep; $scope.toColor = data.stateParams.toColor; $scope.showSendMax = false; $scope.customAmount = data.stateParams.customAmount; - if (!$scope.cardId && !$scope.isGiftCard && !$scope.isGlidera && !$scope.nextStep && !data.stateParams.toAddress) { + if (!$scope.cardId && !$scope.isGlidera && !$scope.nextStep && !data.stateParams.toAddress) { $log.error('Bad params at amount') throw ('bad params'); } @@ -78,7 +78,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ if (data.stateParams.currency) { $scope.alternativeIsoCode = data.stateParams.currency; } else { - $scope.alternativeIsoCode = !!$scope.cardId || !!$scope.isGiftCard ? 'USD' : config.alternativeIsoCode; + $scope.alternativeIsoCode = !!$scope.cardId ? 'USD' : config.alternativeIsoCode; } $scope.specificAmount = $scope.specificAlternativeAmount = ''; $scope.isCordova = platformInfo.isCordova; @@ -118,6 +118,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ }; $scope.toggleAlternative = function() { + if ($scope.forceCurrency) return; $scope.showAlternativeAmount = !$scope.showAlternativeAmount; if ($scope.amount && isExpression($scope.amount)) { @@ -292,64 +293,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ }); }); - } else if ($scope.isGiftCard) { - ongoingProcess.set('Preparing transaction...', true); - // Get first wallet as UUID - var uuid; - try { - uuid = profileService.getWallets({ - onlyComplete: true, - network: amazonService.getEnvironment(), - })[0].id; - } catch (err) { - ongoingProcess.set('Preparing transaction...', false); - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('No wallet found!')); - return; - }; - var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount)); - var dataSrc = { - currency: 'USD', - amount: amountUSD, - uuid: uuid - }; - - amazonService.createBitPayInvoice(dataSrc, function(err, dataInvoice) { - if (err) { - ongoingProcess.set('Preparing transaction...', false); - popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err)); - return; - } - - amazonService.getBitPayInvoice(dataInvoice.invoiceId, function(err, invoice) { - if (err) { - ongoingProcess.set('Preparing transaction...', false); - popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err)); - return; - } - - var payProUrl = invoice.paymentUrls.BIP73; - - payproService.getPayProDetails(payProUrl, function(err, payProDetails) { - ongoingProcess.set('Preparing transaction...', false); - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err)); - return; - } - var stateParams = { - giftCardAmountUSD: amountUSD, - giftCardAccessKey: dataInvoice.accessKey, - giftCardInvoiceTime: invoice.invoiceTime, - giftCardUUID: dataSrc.uuid, - toAmount: payProDetails.amount, - toAddress: payProDetails.toAddress, - description: payProDetails.memo, - paypro: payProDetails - }; - - $state.transitionTo('tabs.giftcards.amazon.confirm', stateParams); - }, true); - }); - }); } else if ($scope.isGlidera) { var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; $state.transitionTo('tabs.buyandsell.glidera.confirm', { diff --git a/src/js/controllers/buyAmazon.js b/src/js/controllers/buyAmazon.js new file mode 100644 index 000000000..b77fd93d5 --- /dev/null +++ b/src/js/controllers/buyAmazon.js @@ -0,0 +1,257 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('buyAmazonController', function($scope, $log, $state, $timeout, $filter, $ionicHistory, lodash, amazonService, popupService, profileService, ongoingProcess, configService, walletService, payproService, bwcError, externalLinkService, platformInfo) { + + var amount; + var currency; + $scope.isCordova = platformInfo.isCordova; + + $scope.openExternalLink = function(url) { + externalLinkService.open(url); + }; + + var showErrorAndBack = function(msg, err) { + $scope.sendStatus = ''; + $log.error(err); + err = err && err.errors ? err.errors[0].message : err; + popupService.showAlert(msg, err, function() { + $ionicHistory.goBack(); + }); + }; + + var showError = function(msg, err) { + $scope.sendStatus = ''; + $log.error(err); + err = err && err.errors ? err.errors[0].message : err; + popupService.showAlert(msg, err); + }; + + var publishAndSign = function (wallet, txp, onSendStatusChange, cb) { + if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { + var err = 'No signing proposal: No private key'; + $log.info(err); + return cb(err); + } + + walletService.publishAndSign(wallet, txp, function(err, txp) { + if (err) return cb(err); + return cb(null, txp); + }, onSendStatusChange); + }; + + var statusChangeHandler = function (processName, showName, isOn) { + $log.debug('statusChangeHandler: ', processName, showName, isOn); + if ( processName == 'buyingGiftCard' && !isOn) { + $scope.sendStatus = 'success'; + $timeout(function() { + $scope.$digest(); + }, 100); + } else if (showName) { + $scope.sendStatus = showName; + } + }; + + var checkTransaction = lodash.throttle(function(count, dataSrc) { + amazonService.createGiftCard(dataSrc, function(err, giftCard) { + $log.debug("creating gift card " + count); + if (err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + giftCard = {}; + giftCard.status = 'FAILURE'; + showError('Error creating gift card', err); + } + + if (giftCard.status == 'PENDING' && count < 3) { + $log.debug("Waiting for payment confirmation"); + checkTransaction(count + 1, dataSrc); + return; + } + + var now = moment().unix() * 1000; + + var newData = giftCard; + newData['invoiceId'] = dataSrc.invoiceId; + newData['accessKey'] = dataSrc.accessKey; + newData['invoiceUrl'] = dataSrc.invoiceUrl; + newData['amount'] = dataSrc.amount; + newData['date'] = dataSrc.invoiceTime || now; + newData['uuid'] = dataSrc.uuid; + + if (newData.status == 'expired') { + amazonService.savePendingGiftCard(newData, { + remove: true + }, function(err) { + $log.error(err); + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Gift card expired'); + return; + }); + } + + amazonService.savePendingGiftCard(newData, null, function(err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + $log.debug("Saving new gift card with status: " + newData.status); + $scope.amazonGiftCard = newData; + }); + }); + }, 8000, { + 'leading': true + }); + + $scope.$on("$ionicView.beforeEnter", function(event, data) { + amount = data.stateParams.amount; + currency = data.stateParams.currency; + + if (amount > 1000) { + showErrorAndBack('Purchase Amount is limited to USD 1000 per day'); + return; + } + + $scope.amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency; + + $scope.network = amazonService.getNetwork(); + $scope.wallets = profileService.getWallets({ + m: 1, // Only 1-signature wallet + onlyComplete: true, + network: $scope.network + }); + $scope.wallet = $scope.wallets[0]; // Default first wallet + }); + + $scope.buyConfirm = function() { + + var message = 'Buy gift card for ' + amount + ' ' + currency; + var okText = 'Confirm'; + var cancelText = 'Cancel'; + popupService.showConfirm(null, message, okText, cancelText, function(ok) { + if (!ok) return; + + var config = configService.getSync(); + var configWallet = config.wallet; + var walletSettings = configWallet.settings; + // Get first wallet as UUID + var uuid = $scope.wallet.id; + var dataSrc = { + currency: currency, + amount: amount, + uuid: uuid + }; + + ongoingProcess.set('buyingGiftCard', true, statusChangeHandler); + amazonService.createBitPayInvoice(dataSrc, function(err, dataInvoice) { + if (err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Error creating BitPay invoice', err); + return; + } + + var accessKey = dataInvoice ? dataInvoice.accessKey : null; + + if (!accessKey) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('No access key defined'); + return; + } + + amazonService.getBitPayInvoice(dataInvoice.invoiceId, function(err, invoice) { + if (err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Error getting BitPay invoice', err); + return; + } + + var payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null; + + if (!payProUrl) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Error fetching invoice'); + return; + } + + payproService.getPayProDetails(payProUrl, function(err, payProDetails) { + if (err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Error fetching payment info', bwcError.msg(err)); + return; + } + + var outputs = []; + var toAddress = payProDetails.toAddress; + var amountSat = payProDetails.amount; + var comment = amount + ' ' + currency + ' Amazon.com Gift Card'; + + outputs.push({ + 'toAddress': toAddress, + 'amount': amountSat, + 'message': comment + }); + + var txp = { + toAddress: toAddress, + amount: amountSat, + outputs: outputs, + message: comment, + payProUrl: payProUrl, + excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, + feeLevel: walletSettings.feeLevel || 'normal' + }; + + walletService.createTx($scope.wallet, txp, function(err, ctxp) { + if (err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Could not create transaction', bwcError.msg(err)); + return; + } + publishAndSign($scope.wallet, ctxp, function() {}, function(err, txSent) { + if (err) { + ongoingProcess.set('buyingGiftCard', false, statusChangeHandler); + showError('Could not send transaction', err); + return; + } + $log.debug('Transaction broadcasted. Waiting for confirmation...'); + var invoiceId = JSON.parse(payProDetails.merchant_data).invoiceId; + var dataSrc = { + currency: currency, + amount: amount, + uuid: uuid, + accessKey: accessKey, + invoiceId: invoice.id, + invoiceUrl: payProUrl, + invoiceTime: invoice.invoiceTime + }; + checkTransaction(1, dataSrc); + }); + }); + }, true); // Disable loader + }); + }); + }); + }; + + $scope.showWalletSelector = function() { + $scope.walletSelectorTitle = 'Buy from'; + $scope.showWallets = true; + }; + + $scope.onWalletSelect = function(wallet) { + $scope.wallet = wallet; + }; + + $scope.goBackHome = function() { + $scope.sendStatus = ''; + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + var claimCode = $scope.amazonGiftCard ? $scope.amazonGiftCard.claimCode : null; + $state.go('tabs.home').then(function() { + $ionicHistory.nextViewOptions({ + disableAnimate: true + }); + $state.transitionTo('tabs.giftcards.amazon').then(function() { + $state.transitionTo('tabs.giftcards.amazon.cards', { cardClaimCode: claimCode }); + }); + }); + }; +}); diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 9e2432e16..def38a854 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -1,25 +1,15 @@ '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, amazonService, 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, glideraService, bwcError, bitpayCardService) { var cachedTxp = {}; var toAmount; var isChromeApp = platformInfo.isChromeApp; var countDown = null; - var giftCardAmountUSD; - var giftCardAccessKey; - var giftCardInvoiceTime; - var giftCardUUID; var cachedSendMax = {}; $scope.isCordova = platformInfo.isCordova; $ionicConfig.views.swipeBackEnabled(false); $scope.$on("$ionicView.beforeEnter", function(event, data) { - // Amazon.com Gift Card parameters - $scope.isGiftCard = data.stateParams.isGiftCard; - giftCardAmountUSD = data.stateParams.giftCardAmountUSD; - giftCardAccessKey = data.stateParams.giftCardAccessKey; - giftCardInvoiceTime = data.stateParams.giftCardInvoiceTime; - giftCardUUID = data.stateParams.giftCardUUID; // Glidera parameters $scope.isGlidera = data.stateParams.isGlidera; @@ -59,7 +49,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.isGiftCard || $scope.cardId) { + if ($scope.isGlidera || $scope.cardId) { $scope.buttonText += gettextCatalog.getString('to complete'); } else if ($scope.paypro) { $scope.buttonText += gettextCatalog.getString('to pay'); @@ -166,8 +156,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.displayUnit = getDisplayUnit($scope.amountStr); if ($scope.cardAmountUSD) { $scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.cardAmountUSD) + ' USD'; - } else if ($scope.giftCardAmountUSD) { - $scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.giftCardAmountUSD) + ' USD'; } else { txFormatService.formatAlternativeStr(toAmount, function(v) { $scope.alternativeAmountStr = v; @@ -599,7 +587,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 fromAmazon = previousView.match(/tabs.giftcards.amazon/) ? true : false; var fromGlidera = previousView.match(/tabs.buyandsell.glidera/) ? true : false; $ionicHistory.nextViewOptions({ @@ -614,17 +601,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( id: $stateParams.cardId }); }, 100); - } else if (fromAmazon) { - $ionicHistory.nextViewOptions({ - disableAnimate: true, - historyRoot: true - }); - $ionicHistory.clearHistory(); - $state.go('tabs.home').then(function() { - $state.transitionTo('tabs.giftcards.amazon', { - cardClaimCode: $scope.amazonGiftCard ? $scope.amazonGiftCard.claimCode : null - }); - }); } else if (fromGlidera) { $ionicHistory.nextViewOptions({ disableAnimate: true, @@ -814,75 +790,9 @@ angular.module('copayApp.controllers').controller('confirmController', function( walletService.publishAndSign(wallet, txp, function(err, txp) { if (err) return setSendError(err); - - var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName; - var fromAmazon = previousView.match(/tabs.giftcards.amazon/) ? true : false; - if (fromAmazon) { - var count = 0; - var invoiceId = JSON.parse($scope.paypro.merchant_data).invoiceId; - var dataSrc = { - currency: 'USD', - amount: giftCardAmountUSD, - uuid: giftCardUUID, - accessKey: giftCardAccessKey, - invoiceId: invoiceId, - invoiceUrl: $scope.paypro.url, - invoiceTime: giftCardInvoiceTime - }; - ongoingProcess.set('creatingGiftCard', true); - debounceCreate(count, dataSrc, onSendStatusChange); - } }, onSendStatusChange); }; - var debounceCreate = lodash.throttle(function(count, dataSrc) { - debounceCreateGiftCard(count, dataSrc); - }, 8000, { - 'leading': true - }); - - var debounceCreateGiftCard = function(count, dataSrc, onSendStatusChange) { - amazonService.createGiftCard(dataSrc, function(err, giftCard) { - $log.debug("creating gift card " + count); - if (err) { - giftCard = {}; - giftCard.status = 'FAILURE'; - popupService.showAlert(gettextCatalog.getString('Error'), err); - } - - if (giftCard.status == 'PENDING' && count < 3) { - $log.debug("pending gift card not available yet"); - debounceCreate(count + 1, dataSrc); - return; - } - - var now = moment().unix() * 1000; - - var newData = giftCard; - newData['invoiceId'] = dataSrc.invoiceId; - newData['accessKey'] = dataSrc.accessKey; - newData['invoiceUrl'] = dataSrc.invoiceUrl; - newData['amount'] = dataSrc.amount; - newData['date'] = dataSrc.invoiceTime || now; - newData['uuid'] = dataSrc.uuid; - - if (newData.status == 'expired') { - amazonService.savePendingGiftCard(newData, { - remove: true - }, function(err) { - $log.error(err); - return; - }); - } - - amazonService.savePendingGiftCard(newData, null, function(err) { - ongoingProcess.set('creatingGiftCard', false); - $log.debug("Saving new gift card with status: " + newData.status); - $scope.amazonGiftCard = newData; - }); - }); - }; - $scope.getRates = function() { var config = configService.getSync().wallet.settings; var unitName = config.unitName; diff --git a/src/js/controllers/modals/amazonCardDetails.js b/src/js/controllers/modals/amazonCardDetails.js index af3778fd3..b1f6539a4 100644 --- a/src/js/controllers/modals/amazonCardDetails.js +++ b/src/js/controllers/modals/amazonCardDetails.js @@ -7,7 +7,7 @@ angular.module('copayApp.controllers').controller('amazonCardDetailsController', amazonService.cancelGiftCard($scope.card, function(err, data) { ongoingProcess.set('cancelingGiftCard', false); if (err) { - popupService.showAlert('Error', bwcError.msg(err)); + popupService.showAlert('Error canceling gift card', bwcError.msg(err)); return; } $scope.card.cardStatus = data.cardStatus; diff --git a/src/js/routes.js b/src/js/routes.js index aa4ac20b7..cc8037381 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -988,44 +988,49 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr */ .state('tabs.giftcards.amazon', { - url: '/amazon', - views: { - 'tab-home@tabs': { - controller: 'amazonController', - templateUrl: 'views/amazon.html' - } - }, - params: { - cardClaimCode: null + url: '/amazon', + views: { + 'tab-home@tabs': { + controller: 'amazonController', + templateUrl: 'views/amazon.html' } - }) - .state('tabs.giftcards.amazon.amount', { - url: '/amount', - views: { - 'tab-home@tabs': { - controller: 'amountController', - templateUrl: 'views/amount.html' - } - }, - params: { - isGiftCard: true, - toName: 'Amazon.com Gift Card' + } + }) + .state('tabs.giftcards.amazon.cards', { + url: '/cards', + views: { + 'tab-home@tabs': { + controller: 'amazonCardsController', + templateUrl: 'views/amazonCards.html' } - }) - .state('tabs.giftcards.amazon.confirm', { - url: '/confirm/:toAmount/:toAddress/:description/:giftCardAmountUSD/:giftCardAccessKey/:giftCardInvoiceTime/:giftCardUUID', - views: { - 'tab-home@tabs': { - controller: 'confirmController', - templateUrl: 'views/confirm.html' - } - }, - params: { - isGiftCard: true, - toName: 'Amazon.com Gift Card', - paypro: null + }, + params: { + cardClaimCode: null + } + }) + .state('tabs.giftcards.amazon.amount', { + url: '/amount', + views: { + 'tab-home@tabs': { + controller: 'amountController', + templateUrl: 'views/amount.html' } - }) + }, + params: { + nextStep: 'tabs.giftcards.amazon.buy', + currency: 'USD', + forceCurrency: true + } + }) + .state('tabs.giftcards.amazon.buy', { + url: '/buy/:amount/:currency', + views: { + 'tab-home@tabs': { + controller: 'buyAmazonController', + templateUrl: 'views/buyAmazon.html' + } + } + }) /* * diff --git a/src/js/services/amazonService.js b/src/js/services/amazonService.js index 4d82bc337..e44166172 100644 --- a/src/js/services/amazonService.js +++ b/src/js/services/amazonService.js @@ -40,13 +40,13 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo }; }; - root.getEnvironment = function() { + root.getNetwork = function() { _setCredentials(); return credentials.NETWORK; }; root.savePendingGiftCard = function(gc, opts, cb) { - var network = root.getEnvironment(); + var network = root.getNetwork(); storageService.getAmazonGiftCards(network, function(err, oldGiftCards) { if (lodash.isString(oldGiftCards)) { oldGiftCards = JSON.parse(oldGiftCards); @@ -74,7 +74,7 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo }; root.getPendingGiftCards = function(cb) { - var network = root.getEnvironment(); + var network = root.getNetwork(); storageService.getAmazonGiftCards(network, function(err, giftCards) { var _gcds = giftCards ? JSON.parse(giftCards) : null; return cb(err, _gcds); diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index df2bccbc9..48a83abf7 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -44,7 +44,8 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti 'updatingGiftCards': 'Updating Gift Cards...', 'updatingGiftCard': 'Updating Gift Card...', 'cancelingGiftCard': 'Canceling Gift Card...', - 'creatingGiftCard': 'Creating Gift Card...' + 'creatingGiftCard': 'Creating Gift Card...', + 'buyingGiftCard': 'Buying Gift Card...' }; root.clear = function() { diff --git a/src/sass/views/integrations/amazon.scss b/src/sass/views/integrations/amazon.scss new file mode 100644 index 000000000..e56535c77 --- /dev/null +++ b/src/sass/views/integrations/amazon.scss @@ -0,0 +1,141 @@ +#amazon { + $item-lateral-padding: 20px; + $item-vertical-padding: 10px; + $item-border-color: #EFEFEF; + $item-label-color: #6C6C6E; + @extend .deflash-blue; + .icon-amazon { + background-image: url("../img/icon-amazon.svg"); + } + .spinner svg { + stroke: black; + fill: black; + } + + .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.8rem; + + img { + margin-right: 1rem; + height: 35px; + width: 35px; + } + + span { + text-transform: capitalize; + } + + .big-icon-svg { + margin-right: 0.6rem; + } + + } + .amount-label{ + line-height: 30px; + .amount{ + font-size: 38px; + margin-bottom: .5rem; + + > .unit { + font-family: "Roboto-Light"; + } + } + .alternative { + font-size: 12px; + 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; + } + } + } + } +} diff --git a/src/sass/views/views.scss b/src/sass/views/views.scss index 351a93298..e26092690 100644 --- a/src/sass/views/views.scss +++ b/src/sass/views/views.scss @@ -43,4 +43,5 @@ @import "includes/walletSelector"; @import "integrations/coinbase"; @import "integrations/glidera"; +@import "integrations/amazon"; @import "custom-amount"; diff --git a/www/views/amazon.html b/www/views/amazon.html index 34faec3d7..7e058a037 100644 --- a/www/views/amazon.html +++ b/www/views/amazon.html @@ -11,14 +11,15 @@ Sandbox version. Only for testing purpose -
+
Amazon.com Gift Card
Only redeemable on www.amazon.com (USA website)
- @@ -29,13 +30,20 @@
-
+
@@ -49,29 +57,6 @@ of Amazon.com, Inc. or its affiliates. No expiration date or service fees.
- -
-
- Your cards -
-
- {{id}} -

- {{item.amount | currency : '$ ' : 2}} -

-

- - -

-

- Error - Pending to confirmation - Canceled - {{item.date | amTimeAgo}} -

-
-
diff --git a/www/views/amazonCards.html b/www/views/amazonCards.html new file mode 100644 index 000000000..a50aa1454 --- /dev/null +++ b/www/views/amazonCards.html @@ -0,0 +1,43 @@ + + + + + Your cards + + + +
+
+ {{id}} + + +

+ {{item.amount | currency : '$ ' : 2}} {{item.currency}} + - +

+

+ Error + Expired + Pending to confirmation + Canceled + {{item.date | amTimeAgo}} +

+
+
+ +
+ * Amazon.com is not a sponsor of this promotion. + Except as required by law, Amazon.com + Gift Cards ("GCs") cannot be transferred for value or redeemed for cash. GCs may be used only for purchases of + eligible goods at Amazon.com or certain of its + affiliated websites. For complete terms and conditions, see + www.amazon.com/gc-legal. + GCs are issued by ACI Gift Cards, Inc., a Washington corporation. All Amazon ®, ™ & © are IP + of Amazon.com, Inc. or its affiliates. + No expiration date or service fees. +
+
+
diff --git a/www/views/amount.html b/www/views/amount.html index 7335118b2..438f7ae53 100644 --- a/www/views/amount.html +++ b/www/views/amount.html @@ -21,7 +21,7 @@ - + @@ -30,11 +30,6 @@
- - -
-
-
{{toName || toAddress}}
@@ -45,7 +40,6 @@
Amount -
Purchase Amount is limited to USD 1000 per day
{{exchangeRate}}
diff --git a/www/views/buyAmazon.html b/www/views/buyAmazon.html new file mode 100644 index 000000000..07529c23c --- /dev/null +++ b/www/views/buyAmazon.html @@ -0,0 +1,100 @@ + + + + + Buy + + + + +
+ +
+
+ +
+
+ Amazon.com Gift Card +
+
+
{{amountUnitStr}}
+
+ Purchase Amount is limited to USD 1000 per day +
+
+
+ +
+
+
From
+
+ + + + {{wallet ? wallet.name : '...'}} +
+ +
+
+
+ * Amazon.com is not a sponsor of this promotion. + Except as required by law, Amazon.com + Gift Cards ("GCs") cannot be transferred for value or redeemed for cash. GCs may be used only for purchases of + eligible goods at Amazon.com or certain of its + affiliated websites. For complete terms and conditions, see + www.amazon.com/gc-legal. + GCs are issued by ACI Gift Cards, Inc., a Washington corporation. All Amazon ®, ™ & © are IP + of Amazon.com, Inc. or its affiliates. + No expiration date or service fees. +
+
+
+ +
+ + + Confirm purchase + + + Slide to buy + + + + Your purchase could not be completed + + + Your purchase was added to the list of pending + + + Bought {{amazonGiftCard.amount}} {{amazonGiftCard.currency}} + +
+ Gift card generated and ready to use. +
+
+ + + +
diff --git a/www/views/modals/amazon-card-details.html b/www/views/modals/amazon-card-details.html index 75e6aa7b1..86e58b2dd 100644 --- a/www/views/modals/amazon-card-details.html +++ b/www/views/modals/amazon-card-details.html @@ -45,6 +45,9 @@ FAILURE + + EXPIRED +
diff --git a/www/views/tab-home.html b/www/views/tab-home.html index 909c332d4..89a1a7fdc 100644 --- a/www/views/tab-home.html +++ b/www/views/tab-home.html @@ -168,7 +168,7 @@
- Buy an Amazon Gift Card + Buy a gift card