From 2fe6ec4c6a81c9692c03768a41eebcaa29610c0a Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 8 Dec 2014 18:26:18 -0300 Subject: [PATCH] send working. Refactor paypro and payment intents --- TODO | 12 +- css/src/main.css | 11 +- js/controllers/copayers.js | 10 +- js/controllers/createProfile.js | 5 +- js/controllers/home.js | 4 +- js/controllers/paymentIntent.js | 49 --- js/controllers/paymentUri.js | 19 + js/controllers/send.js | 534 ++++++++++++----------------- js/controllers/sidebar.js | 4 +- js/controllers/uriPayment.js | 22 -- js/controllers/walletForPayment.js | 57 +++ js/models/Wallet.js | 9 +- js/routes.js | 9 +- js/services/go.js | 34 +- js/services/identityService.js | 23 +- views/copayers.html | 2 - views/modals/paypro.html | 28 ++ views/modals/walletSelection.html | 29 ++ views/paymentIntent.html | 32 -- views/send.html | 20 +- views/uri-payment.html | 16 - 21 files changed, 431 insertions(+), 498 deletions(-) delete mode 100644 js/controllers/paymentIntent.js create mode 100644 js/controllers/paymentUri.js delete mode 100644 js/controllers/uriPayment.js create mode 100644 js/controllers/walletForPayment.js create mode 100644 views/modals/paypro.html create mode 100644 views/modals/walletSelection.html delete mode 100644 views/paymentIntent.html delete mode 100644 views/uri-payment.html diff --git a/TODO b/TODO index 53967d2d9..b47a45bfe 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,2 @@ +- join. on walletComplete! - - homeWallet address...e sta ok? -- receive controller .. owned --- -// pkr.cache = opts.cache; - -(en send.js) -// $rootScope.pendingTxCount = res.pendingForUs; - --- probar payment intent - -// TODO refrescar en 'add' diff --git a/css/src/main.css b/css/src/main.css index 0bcd192a0..1c76dbe45 100644 --- a/css/src/main.css +++ b/css/src/main.css @@ -99,8 +99,17 @@ header .alt-currency { font-weight: 700; } +.green { + color: #1abc9c; +} + +.red { + color: #A02F23; +} + + .alt-currency.green { - background: #1ABC9C; + background: #1abc9c; } .alt-currency.red { diff --git a/js/controllers/copayers.js b/js/controllers/copayers.js index 0fd363eeb..10e011c18 100644 --- a/js/controllers/copayers.js +++ b/js/controllers/copayers.js @@ -3,14 +3,10 @@ angular.module('copayApp.controllers').controller('CopayersController', function($scope, $rootScope, $location) { - if (!$rootScope.wallet.isComplete()) { + $scope.init = function() { $rootScope.title = 'Waiting copayers for ' + $rootScope.wallet.getName(); - } - $scope.loading = false; - $scope.secret = $rootScope.wallet.getSecret(); - - $scope.goToWallet = function() { - $location.path('/homeWallet'); + $scope.loading = false; + $scope.secret = $rootScope.wallet.getSecret(); }; $scope.copayersList = function() { diff --git a/js/controllers/createProfile.js b/js/controllers/createProfile.js index 13dcd9dd5..9a8989ef0 100644 --- a/js/controllers/createProfile.js +++ b/js/controllers/createProfile.js @@ -5,7 +5,10 @@ angular.module('copayApp.controllers').controller('CreateProfileController', fun var _credentials, _firstpin; $scope.init = function() { - identityService.goWalletHome(); + + if ($rootScope.wallet) + go.walletHome(); + $scope.isMobile = isMobile.any(); $scope.createStep = 'storage'; diff --git a/js/controllers/home.js b/js/controllers/home.js index 9a2d99e17..8048343ec 100644 --- a/js/controllers/home.js +++ b/js/controllers/home.js @@ -25,8 +25,8 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc $rootScope.fromEmailConfirmation = false; } - if ($rootScope.iden) { - identityService.goWalletHome(); + if ($rootScope.wallet) { + go.walletHome(); } Compatibility.check($scope); diff --git a/js/controllers/paymentIntent.js b/js/controllers/paymentIntent.js deleted file mode 100644 index 73021c785..000000000 --- a/js/controllers/paymentIntent.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('PaymentIntentController', function($rootScope, $scope, $modal, $location, $timeout, balanceService) { - - $rootScope.title = 'Payment intent'; - - $scope.open = function() { - var modalInstance = $modal.open({ - templateUrl: 'myModalContent.html', - controller: ModalInstanceCtrl - }); - }; - - - // Please note that $modalInstance represents a modal window (instance) dependency. - // It is not the same as the $modal service used above. - - var ModalInstanceCtrl = function($scope, $modalInstance, identityService) { - $scope.loading = true; - $scope.setWallets = function() { - if (!$rootScope.iden) return; - var ret = _.filter($rootScope.iden.listWallets(), function(w) { - return w.balanceInfo && w.balanceInfo.totalBalanceBTC; - }); - $timeout(function() { - $scope.wallets = ret; - $scope.loading = false; - $scope.$digest(); - }, 1000); - }; - if ($rootScope.iden) { - var iden = $rootScope.iden; - iden.on('newWallet', function() { - $scope.setWallets(); - }); - } - $scope.ok = function(selectedItem) { - identityService.setPaymentWallet(selectedItem); - $modalInstance.close(); - }; - - $scope.cancel = function() { - $rootScope.pendingPayment = null; - $modalInstance.close(); - $location.path('/homeWallet'); - }; - }; - -}); diff --git a/js/controllers/paymentUri.js b/js/controllers/paymentUri.js new file mode 100644 index 000000000..9e8ba6da6 --- /dev/null +++ b/js/controllers/paymentUri.js @@ -0,0 +1,19 @@ +var bitcore = require('bitcore'); + +angular.module('copayApp.controllers').controller('paymentUriController', function($rootScope, $scope, $routeParams, $location, go) { + + // Build bitcoinURI with querystring + var query = []; + angular.forEach($location.search(), function(value, key) { + query.push(key + "=" + value); + }); + var queryString = query ? "?" + query.join("&") : ""; + var bitcoinURI = $routeParams.data + queryString; + var uri = new bitcore.BIP21(bitcoinURI); + + if (uri.isValid()) { + $rootScope.pendingPayment = bitcoinURI; + } + + go.home(); +}); diff --git a/js/controllers/send.js b/js/controllers/send.js index af50a2edb..b45130788 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -4,106 +4,116 @@ var preconditions = require('preconditions').singleton(); angular.module('copayApp.controllers').controller('SendController', function($scope, $rootScope, $window, $timeout, $modal, $filter, $location, isMobile, notification, rateService) { - var w = $rootScope.wallet; - preconditions.checkState(w); - preconditions.checkState(w.settings.unitToSatoshi); - - $rootScope.title = w.isShared() ? 'Create Transaction Proposal' : 'Send'; - $scope.loading = false; - $scope.error = $scope.success = null; - var satToUnit = 1 / w.settings.unitToSatoshi; - $scope.defaultFee = bitcore.TransactionBuilder.FEE_PER_1000B_SAT * satToUnit; - $scope.unitToBtc = w.settings.unitToSatoshi / bitcore.util.COIN; - $scope.unitToSatoshi = w.settings.unitToSatoshi; - - $scope.alternativeName = w.settings.alternativeName; - $scope.alternativeIsoCode = w.settings.alternativeIsoCode; - - $scope.isRateAvailable = false; - $scope.rateService = rateService; - $scope.showScanner = false; - $scope.myId = w.getMyCopayerId(); - $scope.isMobile = isMobile.any(); - - rateService.whenAvailable(function() { - $scope.isRateAvailable = true; - $scope.$digest(); - }); - - $scope.setAlternativeAmount = function(w, tx, cb) { - rateService.whenAvailable(function() { - _.each(tx.outs, function(out) { - var valueSat = out.valueSat * w.settings.unitToSatoshi; - out.alternativeAmount = $filter('noFractionNumber')(rateService.toFiat(valueSat, $scope.alternativeIsoCode), 2); - out.alternativeIsoCode = $scope.alternativeIsoCode; - }); - if (cb) return cb(tx); - }); - }; - - /** - * Setting the two related amounts as properties prevents an infinite - * recursion for watches while preserving the original angular updates - * - */ - Object.defineProperty($scope, - "alternative", { - get: function() { - return this._alternative; - }, - set: function(newValue) { - this._alternative = newValue; - if (typeof(newValue) === 'number' && $scope.isRateAvailable) { - this._amount = parseFloat( - (rateService.fromFiat(newValue, $scope.alternativeIsoCode) * satToUnit).toFixed(w.settings.unitDecimals), 10); - } else { - this._amount = 0; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty($scope, - "amount", { - get: function() { - return this._amount; - }, - set: function(newValue) { - this._amount = newValue; - if (typeof(newValue) === 'number' && $scope.isRateAvailable) { - - this._alternative = parseFloat( - (rateService.toFiat(newValue * w.settings.unitToSatoshi, $scope.alternativeIsoCode)).toFixed(2), 10); - } else { - this._alternative = 0; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty($scope, - "address", { - get: function() { - return this._address; - }, - set: function(newValue) { - this._address = newValue; - _onChanged(); - }, - enumerable: true, - configurable: true - }); + var satToUnit, unitToSat, w; $scope.init = function() { - // Empty - }; + w = $rootScope.wallet; + preconditions.checkState(w); + preconditions.checkState(w.settings.unitToSatoshi); - navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; - window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + $rootScope.title = w.isShared() ? 'Create Transaction Proposal' : 'Send'; + $scope.loading = false; + $scope.error = $scope.success = null; + + unitToSat = w.settings.unitToSatoshi; + satToUnit = 1 / w.settings.unitToSatoshi; + + $scope.alternativeName = w.settings.alternativeName; + $scope.alternativeIsoCode = w.settings.alternativeIsoCode; + + $scope.isPayUri = false; + $scope.isRateAvailable = false; + $scope.rateService = rateService; + $scope.showScanner = false; + $scope.myId = w.getMyCopayerId(); + $scope.isMobile = isMobile.any(); + + if ($rootScope.pendingPayment) { + var value; + var pp = $rootScope.pendingPayment; + var amount = (pp.data && pp.data.amount) ? + pp.data.amount * 100000000 * satToUnit : 0; + $scope.setForm(pp.address, amount, pp.data.message) + _onAddressChange(pp); + } + + $scope.setInputs(); + $scope.setScanner(); + + rateService.whenAvailable(function() { + $scope.isRateAvailable = true; + $scope.$digest(); + }); + } + + $scope.setInputs = function() { + /** + * Setting the two related amounts as properties prevents an infinite + * recursion for watches while preserving the original angular updates + * + */ + Object.defineProperty($scope, + "alternative", { + get: function() { + return this._alternative; + }, + set: function(newValue) { + this._alternative = newValue; + if (typeof(newValue) === 'number' && $scope.isRateAvailable) { + this._amount = parseFloat( + (rateService.fromFiat(newValue, $scope.alternativeIsoCode) * satToUnit).toFixed(w.settings.unitDecimals), 10); + } else { + this._amount = 0; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty($scope, + "amount", { + get: function() { + return this._amount; + }, + set: function(newValue) { + this._amount = newValue; + if (typeof(newValue) === 'number' && $scope.isRateAvailable) { + + this._alternative = parseFloat( + (rateService.toFiat(newValue * unitToSat, $scope.alternativeIsoCode)).toFixed(2), 10); + } else { + this._alternative = 0; + } + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty($scope, + "address", { + get: function() { + return this._address; + }, + set: function(newValue) { + this._address = newValue; + _onAddressChange(); + }, + enumerable: true, + configurable: true + }); + }; + + $scope.setScanner = function() { + navigator.getUserMedia = navigator.getUserMedia || + navigator.webkitGetUserMedia || navigator.mozGetUserMedia || + navigator.msGetUserMedia; + window.URL = window.URL || window.webkitURL || + window.mozURL || window.msURL; + + if (!window.cordova && !navigator.getUserMedia) + $scope.disableScanner = 1; + }; - if (!window.cordova && !navigator.getUserMedia) - $scope.disableScanner = 1; $scope._showError = function(err) { copay.logger.error(err); @@ -112,12 +122,8 @@ angular.module('copayApp.controllers').controller('SendController', if (msg.match('BIG')) msg = 'The transaction have too many inputs. Try creating many transactions for smaller amounts' - if (msg.match('totalNeededAmount')) - msg = 'Not enough funds' - - - if (msg.match('unspent not set')) - msg = 'Not enough funds' + if (msg.match('totalNeededAmount') || msg.match('unspent not set')) + msg = 'Insufficient funds' var message = 'The transaction' + (w.isShared() ? ' proposal' : '') + ' could not be created: ' + msg; @@ -135,7 +141,7 @@ angular.module('copayApp.controllers').controller('SendController', $scope.loading = true; var address = form.address.$modelValue; - var amount = parseInt((form.amount.$modelValue * w.settings.unitToSatoshi).toFixed(0)); + var amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0)); var commentText = form.comment.$modelValue; @@ -148,12 +154,6 @@ angular.module('copayApp.controllers').controller('SendController', }; } - // If we're setting the domain, ignore the change. - if ($rootScope.merchant && $rootScope.merchant.domain && address === $rootScope.merchant.domain) { - payInfo = { - merchant: $rootScope.merchant.request_url - }; - } w.spend({ toAddress: address, amountSat: amount, @@ -339,48 +339,30 @@ angular.module('copayApp.controllers').controller('SendController', $scope.notifyStatus(status); if (cb) return cb(); }); - }; - - $scope.clearMerchant = function(callback) { - // TODO: Find a better way of detecting - // whether we're in the Send scope or not. - if (!$scope.sendForm || !$scope.sendForm.address) { - delete $rootScope.merchant; - $rootScope.merchantError = false; - $scope.isPayUri = false; - if (callback) callback(); - return; - } - var val = $scope.sendForm.address.$viewValue || ''; - var uri; - // If we're setting the domain, ignore the change. - if ($rootScope.merchant && $rootScope.merchant.domain && val === $rootScope.merchant.domain) { - uri = { - merchant: $rootScope.merchant.request_url - }; - } - if (val.indexOf('bitcoin:') === 0) { - uri = new bitcore.BIP21(val).data; - } else if (/^https?:\/\//.test(val)) { - uri = { - merchant: val - }; - } - if (!uri || !uri.merchant) { - delete $rootScope.merchant; - $scope.sendForm.amount.$setViewValue(''); - $scope.sendForm.amount.$render(); - if (callback) callback(); - if ($rootScope.$$phase !== '$apply' && $rootScope.$$phase !== '$digest') { - $rootScope.$apply(); - } - } }; - $scope.cancelSend = function(form) { - delete $rootScope.merchant; - $rootScope.merchantError = false; - $scope.isPayUri = false; + $scope.setForm = function(to, amount, comment) { + var form = $scope.sendForm; + form.address.$setViewValue(merchantData.domain); + form.address.$render(); + form.address.$isValid = true; + + form.amount.$setViewValue(merchantData.unitTotal); + form.amount.$render(); + form.amount.$isValid = true; + + if (comment) + $scope.commentText = comment; + }; + + $scope.cancelSend = function(error) { + var form = $scope.sendForm; + + if (error) + $scope.error = error; + + $scope.fetchingURL = null; + $scope.isPayUri = null; form.address.$setViewValue(''); form.address.$render(); form.amount.$setViewValue(''); @@ -388,41 +370,37 @@ angular.module('copayApp.controllers').controller('SendController', form.comment.$setViewValue(''); form.comment.$render(); form.$setPristine(); - }; + }; - var _onChanged = function(pp) { + + $scope.openPPModal = function(pp) { + var ModalInstanceCtrl = function($scope, $modalInstance) { + $scope.pp = pp; + $scope.cancel = function() { + $modalInstance.dismiss('cancel'); + }; + }; + $modal.open({ + templateUrl: 'views/modals/paypro.html', + windowClass: 'tiny', + controller: ModalInstanceCtrl, + }); + }; + + + + var _onAddressChange = function(pp) { var value; - - if (pp) { - $scope.isPayUri = true; - var amount = (pp.data && pp.data.amount) ? pp.data.amount * 100000000 * satToUnit : 0; - $scope.commentText = pp.data.message; - if (pp.data.merchant) { - value = 'bitcoin:' + pp.address.data + '?amount=' + amount + '&r=' + pp.data.r; - } - else { - value = pp.address + ''; - $timeout(function() { - $scope.amount = amount; - }, 1000); - $scope.address = value; - } - } - value = value || $scope.address || ''; var uri; $scope.error = $scope.success = null; - // If we're setting the domain, ignore the change. - if ($rootScope.merchant && $rootScope.merchant.domain && value === $rootScope.merchant.domain) { - return; - } if (value.indexOf('bitcoin:') === 0) { uri = new bitcore.BIP21(value); } else if (/^https?:\/\//.test(value)) { uri = { - data : { + data: { merchant: value } }; @@ -433,7 +411,7 @@ angular.module('copayApp.controllers').controller('SendController', var amount = (uri.data && uri.data.amount) ? uri.data.amount * 100000000 * satToUnit : 0; var address = uri.address.data; if (amount && address) { - $scope.isPayUri = true; + $scope.isPayUri = {fixedAmount: true} ; } $timeout(function() { $scope.amount = amount; @@ -444,178 +422,106 @@ angular.module('copayApp.controllers').controller('SendController', return; } - var apply = function() { - if ($rootScope.$$phase !== '$apply' && $rootScope.$$phase !== '$digest') { - $rootScope.$apply(); - } - }; - $scope.fetchingURL = uri.data.merchant; $scope.loading = true; - apply(); - var timeout = setTimeout(function() { - timeout = null; - $scope.fetchingURL = null; - $scope.loading = false; - $scope.sendForm.address.$setViewValue(''); - $scope.sendForm.address.$render(); - $scope.sendForm.address.$isValid = false; - $scope.error = 'Payment server timed out'; - apply(); - }, 10 * 1000); + + var balance = w.balanceInfo.availableBalance; + var available = +(balance * unitToSat).toFixed(0); // Payment Protocol URI (BIP-72) $scope.wallet.fetchPaymentRequest({ url: uri.data.merchant }, function(err, merchantData) { - if (!timeout) return; - clearTimeout(timeout); - $scope.loading = false; $scope.fetchingURL = null; - apply(); - - var balance = $rootScope.availableBalance; - var available = +(balance * w.settings.unitToSatoshi).toFixed(0); - if (merchantData && available < +merchantData.total) { - err = new Error('Insufficient funds.'); - err.amount = merchantData.total; - } if (err) { - if (err.amount) { - $scope.sendForm.amount.$setViewValue(+err.amount / w.settings.unitToSatoshi); - $scope.sendForm.amount.$render(); - $scope.sendForm.amount.$isValid = false; - $scope.notEnoughAmount = true; - $rootScope.merchantError = true; - var lastAddr = $scope.sendForm.address.$viewValue; - var unregister = $scope.$watch('address', function() { - if ($scope.sendForm.address.$viewValue !== lastAddr) { - delete $rootScope.merchantError; - $scope.isPayUri = false; - $scope.sendForm.amount.$setViewValue(''); - $scope.sendForm.amount.$render(); - unregister(); - apply(); - } - }); + if (err.match('TIMEOUT')) { + $scope.cancelSend('Payment server timed out'); } else { - $scope.sendForm.address.$setViewValue(''); - $scope.sendForm.address.$render(); + $scope.cancelSend(err.toString()); } - $scope.sendForm.address.$isValid = false; - copay.logger.error(err); - $scope.error = 'Could not fetch payment request'; - - apply(); - return; + } else if (merchantData && available < +merchantData.total) { + $scope.cancelSend(err.toString('Insufficient funds')); + } else { + $scope.setForm(merchantData.domain, merchantData.unitTotal) } - - var url = merchantData.request_url; - var domain = /^(?:https?)?:\/\/([^\/:]+).*$/.exec(url)[1]; - - merchantData.unitTotal = (+merchantData.total / w.settings.unitToSatoshi) + ''; - merchantData.expiration = new Date( - merchantData.pr.pd.expires * 1000); - merchantData.domain = domain; - - $rootScope.merchant = merchantData; - - $scope.sendForm.address.$setViewValue(domain); - $scope.sendForm.address.$render(); - $scope.sendForm.address.$isValid = true; - - $scope.sendForm.amount.$setViewValue(merchantData.unitTotal); - $scope.sendForm.amount.$render(); - $scope.sendForm.amount.$isValid = true; - - // If the address changes to a non-payment-protocol one, - // delete the `merchant` property from the scope. - var unregister = $rootScope.$watch(function() { - $scope.clearMerchant(unregister); - }); - - apply(); + $timeout(function() { + $scope.$digest(); + }, 1); }); }; - if ($rootScope.pendingPayment) { - var value; - var pp = $rootScope.pendingPayment; - _onChanged(pp); - } - $scope.openAddressBook = function() { var modalInstance = $modal.open({ templateUrl: 'views/modals/address-book.html', - windowClass: 'large', - controller: function($scope, $modalInstance) { + windowClass: 'large', + controller: function($scope, $modalInstance) { - $scope.showForm = null; - $scope.addressBook = w.addressBook; + $scope.showForm = null; + $scope.addressBook = w.addressBook; - $scope.hasEntry = function() { - return _.keys($scope.addressBook).length > 0 ? true : false; - }; + $scope.hasEntry = function() { + return _.keys($scope.addressBook).length > 0 ? true : false; + }; - $scope.toggleAddressBookEntry = function(key) { - w.toggleAddressBookEntry(key); - }; + $scope.toggleAddressBookEntry = function(key) { + w.toggleAddressBookEntry(key); + }; - $scope.copyToSend = function(addr) { - $modalInstance.close(addr); - }; + $scope.copyToSend = function(addr) { + $modalInstance.close(addr); + }; - $scope.cancel = function() { - $scope.error = $scope.success = null; - $scope.toggleForm(); - }; + $scope.cancel = function() { + $scope.error = $scope.success = null; + $scope.toggleForm(); + }; - $scope.toggleForm = function() { - $scope.showForm = !$scope.showForm; - }; - - $scope.submitAddressBook = function(form) { - if (form.$invalid) { - return; - } - $timeout(function() { - var errorMsg; - var entry = { - "address": form.newaddress.$modelValue, - "label": form.newlabel.$modelValue - }; - try { - w.setAddressBook(entry.address, entry.label); - } catch (e) { - console.log('[send.js:583]',e); //TODO - errorMsg = e.message; - } - - if (errorMsg) { - $scope.error = errorMsg; - } else { - $scope.toggleForm(); - $scope.success = 'New entry has been created'; - } - $rootScope.$digest(); - }, 500); - - $timeout(function() { - $scope.error = $scope.success = null; - }, 5000); + $scope.toggleForm = function() { + $scope.showForm = !$scope.showForm; + }; + $scope.submitAddressBook = function(form) { + if (form.$invalid) { return; - - }; + } + $timeout(function() { + var errorMsg; + var entry = { + "address": form.newaddress.$modelValue, + "label": form.newlabel.$modelValue + }; + try { + w.setAddressBook(entry.address, entry.label); + } catch (e) { + console.log('[send.js:583]', e); //TODO + errorMsg = e.message; + } - $scope.close = function() { - $modalInstance.dismiss('cancel'); - }; - }, + if (errorMsg) { + $scope.error = errorMsg; + } else { + $scope.toggleForm(); + $scope.success = 'New entry has been created'; + } + $rootScope.$digest(); + }, 500); + + $timeout(function() { + $scope.error = $scope.success = null; + }, 5000); + + return; + + }; + + $scope.close = function() { + $modalInstance.dismiss('cancel'); + }; + }, }); modalInstance.result.then(function(addr) { diff --git a/js/controllers/sidebar.js b/js/controllers/sidebar.js index b14d23d93..aeba65e86 100644 --- a/js/controllers/sidebar.js +++ b/js/controllers/sidebar.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('SidebarController', function($scope, $rootScope, $location, $timeout, identityService, isMobile) { +angular.module('copayApp.controllers').controller('SidebarController', function($scope, $rootScope, $location, $timeout, identityService, isMobile, go) { $scope.isMobile = isMobile.any() @@ -37,7 +37,7 @@ angular.module('copayApp.controllers').controller('SidebarController', function( $scope.switchWallet = function(wid) { $scope.walletSelection = false; identityService.setFocusedWallet(wid); - identityService.goWalletHome(); + go.walletHome(); }; $scope.toggleWalletSelection = function() { diff --git a/js/controllers/uriPayment.js b/js/controllers/uriPayment.js deleted file mode 100644 index 486a09be7..000000000 --- a/js/controllers/uriPayment.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -var bitcore = require('bitcore'); - -angular.module('copayApp.controllers').controller('UriPaymentController', function($rootScope, $scope, $routeParams, $timeout, $location) { - // Build bitcoinURI with querystring - var query = []; - angular.forEach($location.search(), function(value, key) { - query.push(key + "=" + value); - }); - var queryString = query ? "?" + query.join("&") : ""; - var bitcoinURI = $routeParams.data + queryString; - - $rootScope.pendingPayment = new bitcore.BIP21(bitcoinURI); - - $timeout(function() { - console.log('Redirecting to /paymentIntent'); - $location.path('/paymentIntent'); - }, 1000); - - -}); diff --git a/js/controllers/walletForPayment.js b/js/controllers/walletForPayment.js new file mode 100644 index 000000000..12a8fa9e7 --- /dev/null +++ b/js/controllers/walletForPayment.js @@ -0,0 +1,57 @@ +var bitcore = require('bitcore'); + +angular.module('copayApp.controllers').controller('walletForPaymentController', function($rootScope, $scope, $modal, go) { + +console.log('[walletForPayment.js.4]'); //TODO + if (!$rootScope.pendingPayment) { + go.walletHome(); + } else { + +console.log('[walletForPayment.js.9]'); //TODO + $scope.selectWallet(function(w) { + if (w) { + identityService.setFocusedWallet(w); + go.send(); + } else { + go.walletHome(); + } + }); + } + + $scope.selectWallet = function(cb) { + +console.log('[walletForPayment.js.22]'); //TODO + var ModalInstanceCtrl = function($scope, $modalInstance, $identityService) { + $scope.loading = true; + preconditions.checkState($rootScope.iden); + + var iden = $rootScope.iden; + iden.on('newWallet', function() { + $scope.setWallets(); + }); + + $scope.setWallets = function() { + $scope.wallets = _.filter($rootScope.iden.listWallets(), function(w) { + return w.balanceInfo && w.balanceInfo.totalBalanceBTC; + }); + }; + + $scope.ok = function(w) { + $modalInstance.close(); + return cb(w); + }; + + $scope.cancel = function() { + $modalInstance.close(); + return cb(); + }; + }; + +console.log('[walletForPayment.js.49]'); //TODO + $modal.open({ + templateUrl: 'views/modals/walletSelect.html', + windowClass: 'tiny', + controller: ModalInstanceCtrl, + }); + }; +}); diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 44543c349..43993fa27 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -1793,6 +1793,7 @@ Wallet.prototype.parsePaymentRequest = function(options, rawData) { var payment_url = pd.get('payment_url'); var merchant_data = pd.get('merchant_data'); + var total = bignum('0', 10).toString(10); var merchantData = { pr: { payment_details_version: ver, @@ -1826,8 +1827,12 @@ Wallet.prototype.parsePaymentRequest = function(options, rawData) { }, expires: expires, request_url: options.url, - total: bignum('0', 10).toString(10), + domain: /^(?:https?)?:\/\/([^\/:]+).*$/.exec(options.url)[1], + total: total, + unitTotal: total ? (+total / w.settings.unitToSatoshi) + '' : null, + expirationDate: expires ? new Date(expires * 1000) : null, }; + this._addOutputsToMerchantData(merchantData, options.amount); return merchantData; }; @@ -2546,7 +2551,7 @@ Wallet.prototype.isComplete = function() { /** * @desc Sets the version of this wallet object - * + * * @param {string} version - the new version for the wallet */ Wallet.prototype.setVersion = function(version) { diff --git a/js/routes.js b/js/routes.js index c295994b4..d6f3e7245 100644 --- a/js/routes.js +++ b/js/routes.js @@ -22,11 +22,14 @@ angular template: " ", // just fire controller controller: 'EmailConfirmationController', }) + // Payment intents come here. .when('/uri-payment/:data', { - templateUrl: 'views/uri-payment.html' + template: " ", // just fire controller + controller: 'paymentUriController', }) - .when('/paymentIntent', { - templateUrl: 'views/paymentIntent.html', + .when('/selectWalletForPayment', { + template: " ", // just fire controller + controller: 'walletForPaymentController', logged: true }) .when('/join', { diff --git a/js/services/go.js b/js/services/go.js index 550693288..5159c8a90 100644 --- a/js/services/go.js +++ b/js/services/go.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.services').factory('go', function($window, $location) { +angular.module('copayApp.services').factory('go', function($window, $rootScope, $location) { var root = {}; var hideSidebars = function() { @@ -44,7 +44,7 @@ angular.module('copayApp.services').factory('go', function($window, $location) { var ref = window.open(url, '_blank', 'location=no'); }; - root.go = function(path) { + root.path = function(path) { var parts = path.split('#'); $location.path(parts[0]); if (parts[1]) @@ -56,5 +56,35 @@ angular.module('copayApp.services').factory('go', function($window, $location) { toggleSidebar(invert); }; + root.walletHome = function() { +console.log('[go.js.25:walletHome:]'); //TODO + var w = $rootScope.wallet; + preconditions.checkState(w); + $rootScope.starting = false; + if (!w.isComplete()) { + root.path('copayers'); + } else { + if ($rootScope.pendingPayment) { + root.path('selectWalletForPayment'); + } else { + +console.log('[go.js.36]'); //TODO + root.path('homeWallet'); + } + } + }; + + root.home = function() { + if ($rootScope.iden) + root.walletHome(); + else + root.path('/'); + }; + + + root.send = function() { + $location.path('send'); + }; + return root; }); diff --git a/js/services/identityService.js b/js/services/identityService.js index 5620e8e49..3ec89d4c5 100644 --- a/js/services/identityService.js +++ b/js/services/identityService.js @@ -27,23 +27,6 @@ angular.module('copayApp.services') }); }; - // TODO should be on 'walletService' or 'go' - root.goWalletHome = function() { - var w = $rootScope.wallet; - if (w) { - $rootScope.starting = false; - if (!w.isComplete()) { - go.go('copayers'); - } else { - if ($rootScope.pendingPayment) { - go.go('paymentIntent'); - } else { - go.go('homeWallet'); - } - } - } - }; - root.create = function(email, password, cb) { copay.Identity.create({ email: email, @@ -133,10 +116,6 @@ angular.module('copayApp.services') $rootScope.iden = iden; }; - root.setPaymentWallet = function(w) { - root.setFocusedWallet(w); - $location.path('/send'); - }; root.noFocusedWallet = function() { $rootScope.wallet = null; @@ -296,7 +275,7 @@ angular.module('copayApp.services') if (wid == iden.getLastFocusedWalletId()) { copay.logger.debug('GOT Focused wallet:', w.getName()); root.setFocusedWallet(w, true); - root.goWalletHome(); + go.walletHome(); } // At the end (after all handlers are in place)...start the wallet. diff --git a/views/copayers.html b/views/copayers.html index 12c4a6a04..f2477315b 100644 --- a/views/copayers.html +++ b/views/copayers.html @@ -1,6 +1,4 @@
-
-

diff --git a/views/modals/paypro.html b/views/modals/paypro.html new file mode 100644 index 000000000..399a6ab16 --- /dev/null +++ b/views/modals/paypro.html @@ -0,0 +1,28 @@ +× + +
+

Payment Protocol Request

+ +

+ Signature: + {{$root.merchant.pr.ca}} + Untrusted +

+ Merchant Message: + {{$root.merchant.pr.pd.memo || address}} +

+ +

+ Merchant Message: + {{amount}} {{$root.wallet.settings.unitName}} + + {{ alternative }} {{ alternativeIsoCode }} + +

+ Expires {{$root.merchant.expiration | amTimeAgo }} [{{$root.merchant.domain}}] +

+
+ +

+ + diff --git a/views/modals/walletSelection.html b/views/modals/walletSelection.html new file mode 100644 index 000000000..092bc9d87 --- /dev/null +++ b/views/modals/walletSelection.html @@ -0,0 +1,29 @@ + × + +

Select a wallet to make the payment

+Loading... + + diff --git a/views/paymentIntent.html b/views/paymentIntent.html deleted file mode 100644 index 4a1fb750a..000000000 --- a/views/paymentIntent.html +++ /dev/null @@ -1,32 +0,0 @@ -
- -
diff --git a/views/send.html b/views/send.html index 03771d58e..e5db67f6d 100644 --- a/views/send.html +++ b/views/send.html @@ -48,7 +48,7 @@
-
@@ -87,7 +87,7 @@
@@ -112,8 +112,7 @@
@@ -136,10 +135,13 @@
-

This is a payment protocol transaction

-
+

Payment Protocol Request

+

- {{$root.merchant.pr.pd.memo || address}} + {{$root.merchant.pr.ca}} + Untrusted + + {{$root.merchant.pr.pd.memo || address}}

@@ -150,9 +152,7 @@

Expires {{$root.merchant.expiration | amTimeAgo }} [{{$root.merchant.domain}}] - {{$root.merchant.pr.ca}} - Untrusted -

+

diff --git a/views/uri-payment.html b/views/uri-payment.html deleted file mode 100644 index 6d7de2b45..000000000 --- a/views/uri-payment.html +++ /dev/null @@ -1,16 +0,0 @@ -
- -
-
-
-
 
-
 
-
 
-
 
-
- Preparing payment... -
-
- -
-