mirror of https://github.com/BTCPrivate/copay.git
Merge pull request #2060 from matiu/bug/payment-intent
Bug/payment intent
This commit is contained in:
commit
c2598b2646
13
TODO
13
TODO
|
@ -1,12 +1 @@
|
|||
|
||||
- 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'
|
||||
- addressbock
|
||||
|
|
|
@ -99,8 +99,16 @@ header .alt-currency {
|
|||
font-weight: 700;
|
||||
}
|
||||
|
||||
.color-greeni {
|
||||
color: #1abc9c !important;
|
||||
}
|
||||
|
||||
.color-yellowi {
|
||||
color: yellow !important;
|
||||
}
|
||||
|
||||
.alt-currency.green {
|
||||
background: #1ABC9C;
|
||||
background: #1abc9c;
|
||||
}
|
||||
|
||||
.alt-currency.red {
|
||||
|
@ -409,20 +417,6 @@ a:hover {
|
|||
border-radius: 3px 3px 0 3px;
|
||||
}
|
||||
|
||||
a.missing-copayers {
|
||||
background: #7A8C9E;
|
||||
position: absolute;
|
||||
display: block;
|
||||
right: -1px;
|
||||
bottom: -18px;
|
||||
padding: 0.2rem 0.5rem;
|
||||
font-size: 10px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
ul.tx-copayers {
|
||||
background: #E4E8EC;
|
||||
padding: 0.3rem 0.8rem;
|
||||
|
|
|
@ -1,22 +1,33 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('CopayersController',
|
||||
function($scope, $rootScope, $location) {
|
||||
function($scope, $rootScope, $timeout, go) {
|
||||
|
||||
if (!$rootScope.wallet.isComplete()) {
|
||||
console.log('[copayers.js.5]'); //TODO
|
||||
|
||||
$scope.init = function() {
|
||||
var w = $rootScope.wallet;
|
||||
$rootScope.title = 'Waiting copayers for ' + $rootScope.wallet.getName();
|
||||
}
|
||||
$scope.loading = false;
|
||||
$scope.secret = $rootScope.wallet.getSecret();
|
||||
$scope.loading = false;
|
||||
$scope.secret = $rootScope.wallet.getSecret();
|
||||
|
||||
$scope.goToWallet = function() {
|
||||
$location.path('/homeWallet');
|
||||
w.on('publicKeyRingUpdated', $scope.updateList);
|
||||
w.on('ready', $scope.updateList);
|
||||
$scope.updateList();
|
||||
};
|
||||
|
||||
$scope.copayersList = function() {
|
||||
if ($rootScope.wallet) {
|
||||
$scope.copayers = $rootScope.wallet.getRegisteredPeerIds();
|
||||
$scope.updateList = function() {
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
$scope.copayers = $rootScope.wallet.getRegisteredPeerIds();
|
||||
if (w.isComplete()) {
|
||||
|
||||
w.removeListener('publicKeyRingUpdated', $scope.updateList);
|
||||
w.removeListener('ready', $scope.updateList);
|
||||
go.walletHome();
|
||||
}
|
||||
return $scope.copayers;
|
||||
}
|
||||
$timeout(function() {
|
||||
$rootScope.$digest();
|
||||
}, 1);
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -5,7 +5,7 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc
|
|||
// Global go. This should be in a better place TODO
|
||||
// We dont do a 'go' directive, to use the benefits of ng-touch with ng-click
|
||||
$rootScope.go = function (path) {
|
||||
go.go(path);
|
||||
go.path(path);
|
||||
};
|
||||
|
||||
var _credentials, _firstpin;
|
||||
|
@ -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);
|
||||
|
@ -178,7 +178,7 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getParam(sname) {
|
||||
var params = location.search.substr(location.search.indexOf("?") + 1);
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('HomeWalletController', function($scope, $rootScope, $timeout, $filter, $location, rateService, notification, identityService) {
|
||||
$scope.init = function() {
|
||||
angular.module('copayApp.controllers').controller('HomeWalletController', function($scope, $rootScope, $timeout, $filter, $modal, rateService, notification, txStatus, identityService) {
|
||||
$scope.initHome = function() {
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
$rootScope.title = 'Home';
|
||||
|
||||
|
||||
$scope.rateService = rateService;
|
||||
$scope.isRateAvailable = false;
|
||||
|
||||
var w = $rootScope.wallet;
|
||||
w.on('txProposalEvent', _updateTxs);
|
||||
if (w.isShared())
|
||||
$scope.copayers = w.getRegisteredPeerIds();
|
||||
|
||||
w.on('txProposalEvent', _updateTxs);
|
||||
_updateTxs();
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
|
@ -18,7 +20,9 @@ angular.module('copayApp.controllers').controller('HomeWalletController', functi
|
|||
});
|
||||
};
|
||||
|
||||
// This is necesarry, since wallet can change in homeWallet, without running init() again.
|
||||
// This is necessary, since wallet can change in homeWallet,
|
||||
// without running init() again.
|
||||
|
||||
var removeWatch;
|
||||
removeWatch = $rootScope.$watch('wallet.id', function(newWallet, oldWallet) {
|
||||
if ($rootScope.wallet && $rootScope.wallet.isComplete() && newWallet !== oldWallet) {
|
||||
|
@ -40,23 +44,7 @@ angular.module('copayApp.controllers').controller('HomeWalletController', functi
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
// TODO duplicated on controller send. move to a service.
|
||||
$scope.notifyStatus = function(status) {
|
||||
if (status == copay.Wallet.TX_BROADCASTED)
|
||||
notification.success('Success', 'Transaction broadcasted!');
|
||||
else if (status == copay.Wallet.TX_PROPOSAL_SENT)
|
||||
notification.info('Success', 'Transaction proposal created');
|
||||
else if (status == copay.Wallet.TX_SIGNED)
|
||||
notification.success('Success', 'Transaction proposal was signed');
|
||||
else if (status == copay.Wallet.TX_SIGNED_AND_BROADCASTED)
|
||||
notification.success('Success', 'Transaction signed and broadcasted!');
|
||||
else
|
||||
notification.error('Error', 'Unknown error occured');
|
||||
};
|
||||
|
||||
|
||||
$scope.$on("$destroy", function() {
|
||||
$scope.$on("$destroy", function() {
|
||||
var w = $rootScope.wallet;
|
||||
if (w) {
|
||||
removeWatch();
|
||||
|
@ -109,7 +97,8 @@ angular.module('copayApp.controllers').controller('HomeWalletController', functi
|
|||
$scope.error = $scope.success = null;
|
||||
w.signAndSend(ntxid, function(err, id, status) {
|
||||
$scope.loading = false;
|
||||
$scope.notifyStatus(status);
|
||||
if (!txStatus.notify(status))
|
||||
$scope.error = status;
|
||||
_updateTxs();
|
||||
});
|
||||
};
|
||||
|
@ -117,8 +106,32 @@ angular.module('copayApp.controllers').controller('HomeWalletController', functi
|
|||
$scope.reject = function(ntxid) {
|
||||
var w = $rootScope.wallet;
|
||||
w.reject(ntxid);
|
||||
notification.warning('Transaction rejected', 'You rejected the transaction successfully');
|
||||
txStatus.notify('txRejected');
|
||||
_updateTxs();
|
||||
};
|
||||
|
||||
|
||||
$scope.openTxModal = function(tx) {
|
||||
var ModalInstanceCtrl = function($scope, $modalInstance) {
|
||||
$scope.tx = tx;
|
||||
|
||||
$scope.getShortNetworkName = function() {
|
||||
var w = $rootScope.wallet;
|
||||
return w.getNetworkName().substring(0, 4);
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
};
|
||||
|
||||
$modal.open({
|
||||
templateUrl: 'views/modals/txp-details.html',
|
||||
windowClass: 'tiny',
|
||||
controller: ModalInstanceCtrl,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
};
|
||||
};
|
||||
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
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("&") : null;
|
||||
var bitcoinURI = $routeParams.data + ( queryString ? '?' + queryString : '');
|
||||
var uri = new bitcore.BIP21(bitcoinURI);
|
||||
|
||||
if (uri && uri.address && (_.isString(uri.address) || uri.address.isValid()) ) {
|
||||
copay.logger.debug('Payment Intent:', bitcoinURI);
|
||||
$rootScope.pendingPayment = bitcoinURI;
|
||||
}
|
||||
|
||||
go.home();
|
||||
});
|
|
@ -21,10 +21,8 @@ angular.module('copayApp.controllers').controller('ReceiveController',
|
|||
var lastAddr = _.first(w.getAddressesOrderer());
|
||||
var balance = w.balanceInfo.balanceByAddr;
|
||||
|
||||
if (balance[lastAddr]>0)
|
||||
$scope.loading = true;
|
||||
|
||||
while (balance && balance[lastAddr] > 0) {
|
||||
$scope.loading = true;
|
||||
$scope.newAddr();
|
||||
lastAddr = w.generateAddress(null);
|
||||
};
|
||||
|
|
|
@ -3,172 +3,168 @@ var bitcore = require('bitcore');
|
|||
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
|
||||
});
|
||||
function($scope, $rootScope, $window, $timeout, $modal, $filter, notification, isMobile, rateService, txStatus) {
|
||||
|
||||
var satToUnit;
|
||||
|
||||
$scope.init = function() {
|
||||
// Empty
|
||||
};
|
||||
var 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;
|
||||
|
||||
if (!window.cordova && !navigator.getUserMedia)
|
||||
$scope.disableScanner = 1;
|
||||
satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
|
||||
$scope._showError = function(err) {
|
||||
copay.logger.error(err);
|
||||
$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();
|
||||
|
||||
if ($rootScope.pendingPayment) {
|
||||
$timeout(function() {
|
||||
$scope.setFromUri($rootScope.pendingPayment)
|
||||
$rootScope.pendingPayment = null;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
$scope.setInputs();
|
||||
$scope.setScanner();
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$scope.isRateAvailable = true;
|
||||
$scope.$digest();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.setInputs = function() {
|
||||
var w = $rootScope.wallet;
|
||||
var unitToSat = w.settings.unitToSatoshi;
|
||||
/**
|
||||
* 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 = $scope.onAddressChange(newValue);
|
||||
},
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
$scope.setError = function(err) {
|
||||
var w = $rootScope.wallet;
|
||||
copay.logger.warn(err);
|
||||
|
||||
var msg = err.toString();
|
||||
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('totalNeededAmount') || msg.match('unspent not set'))
|
||||
msg = 'Insufficient funds'
|
||||
|
||||
|
||||
if (msg.match('unspent not set'))
|
||||
msg = 'Not enough funds'
|
||||
if (msg.match('expired'))
|
||||
msg = 'The payment request has expired';
|
||||
|
||||
var message = 'The transaction' + (w.isShared() ? ' proposal' : '') +
|
||||
' could not be created: ' + msg;
|
||||
|
||||
$scope.error = message;
|
||||
$scope.loading = false;
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
$scope.submitForm = function(form) {
|
||||
var w = $rootScope.wallet;
|
||||
var unitToSat = w.settings.unitToSatoshi;
|
||||
|
||||
if (form.$invalid) {
|
||||
$scope.error = 'Unable to send transaction proposal';
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.loading = true;
|
||||
|
||||
var address = form.address.$modelValue;
|
||||
var amount = parseInt((form.amount.$modelValue * w.settings.unitToSatoshi).toFixed(0));
|
||||
var commentText = form.comment.$modelValue;
|
||||
|
||||
|
||||
var payInfo;
|
||||
if (address.indexOf('bitcoin:') === 0) {
|
||||
payInfo = (new bitcore.BIP21(address)).data;
|
||||
} else if (/^https?:\/\//.test(address)) {
|
||||
payInfo = {
|
||||
merchant: address
|
||||
};
|
||||
var comment = form.comment.$modelValue;
|
||||
var merchantData = $scope._merchantData;
|
||||
var address, amount;
|
||||
if (!merchantData) {
|
||||
address = form.address.$modelValue;
|
||||
amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0));
|
||||
}
|
||||
|
||||
// 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({
|
||||
merchantData: merchantData,
|
||||
toAddress: address,
|
||||
amountSat: amount,
|
||||
comment: commentText,
|
||||
url: (payInfo && payInfo.merchant) ? payInfo.merchant : null,
|
||||
comment: comment,
|
||||
}, function(err, txid, status) {
|
||||
$scope.loading = false;
|
||||
// reset fields
|
||||
$scope.address = $scope.amount = $scope.commentText = null;
|
||||
form.address.$pristine = form.amount.$pristine = true;
|
||||
$rootScope.pendingPayment = null;
|
||||
$scope.isPayUri = null;
|
||||
if (err) return $scope._showError(err);
|
||||
|
||||
$scope.notifyStatus(status);
|
||||
if (err)
|
||||
return $scope.setError(err);
|
||||
|
||||
$scope.resetForm(status);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -253,7 +249,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
|
||||
qrcode.callback = function(data) {
|
||||
_scanStop();
|
||||
|
||||
$scope.$apply(function() {
|
||||
$scope.sendForm.address.$setViewValue(data);
|
||||
$scope.sendForm.address.$render();
|
||||
|
@ -309,318 +304,251 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
}
|
||||
|
||||
$scope.setTopAmount = function() {
|
||||
$scope.amount = $rootScope.topAmount;
|
||||
var w = $rootScope.wallet;
|
||||
var form = $scope.sendForm;
|
||||
if (form) {
|
||||
form.amount.$setViewValue(w.balanceInfo.topAmount);
|
||||
form.amount.$render();
|
||||
form.amount.$isValid = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.notifyStatus = function(status) {
|
||||
if (status == copay.Wallet.TX_BROADCASTED)
|
||||
$scope.success = 'Transaction broadcasted!';
|
||||
else if (status == copay.Wallet.TX_PROPOSAL_SENT)
|
||||
$scope.success = 'Transaction proposal created';
|
||||
else if (status == copay.Wallet.TX_SIGNED)
|
||||
$scope.success = 'Transaction proposal was signed';
|
||||
else if (status == copay.Wallet.TX_SIGNED_AND_BROADCASTED)
|
||||
$scope.success = 'Transaction signed and broadcasted!';
|
||||
else
|
||||
$scope.error = 'Unknown error occured';
|
||||
var msg;
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
});
|
||||
if (status == copay.Wallet.TX_BROADCASTED)
|
||||
msg = 'Transaction broadcasted!';
|
||||
else if (status == copay.Wallet.TX_PROPOSAL_SENT)
|
||||
msg = 'Transaction proposal created';
|
||||
else if (status == copay.Wallet.TX_SIGNED)
|
||||
msg = 'Transaction proposal was signed';
|
||||
else if (status == copay.Wallet.TX_SIGNED_AND_BROADCASTED)
|
||||
msg = 'Transaction signed and broadcasted!';
|
||||
|
||||
if (msg)
|
||||
$scope.openTxStatusModal(msg);
|
||||
else
|
||||
$scope.error = status;
|
||||
};
|
||||
|
||||
|
||||
$scope.send = function(ntxid, cb) {
|
||||
var w = $rootScope.wallet;
|
||||
$scope.error = $scope.success = null;
|
||||
$scope.loading = true;
|
||||
$rootScope.txAlertCount = 0;
|
||||
w.issueTx(ntxid, function(err, txid, status) {
|
||||
$scope.loading = false;
|
||||
$scope.notifyStatus(status);
|
||||
$scope.resetForm(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;
|
||||
$scope.setForm = function(to, amount, comment) {
|
||||
var form = $scope.sendForm;
|
||||
if (to) {
|
||||
form.address.$setViewValue(to);
|
||||
form.address.$isValid = true;
|
||||
form.address.$render();
|
||||
$scope.lockAddress = true;
|
||||
}
|
||||
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 (amount) {
|
||||
form.amount.$setViewValue("" + amount);
|
||||
form.amount.$isValid = true;
|
||||
form.amount.$render();
|
||||
$scope.lockAmount = true;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
form.comment.$setViewValue(comment);
|
||||
form.comment.$isValid = true;
|
||||
form.comment.$render();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelSend = function(form) {
|
||||
delete $rootScope.merchant;
|
||||
$rootScope.merchantError = false;
|
||||
$scope.isPayUri = false;
|
||||
form.address.$setViewValue('');
|
||||
form.address.$render();
|
||||
$scope.resetForm = function(status) {
|
||||
var form = $scope.sendForm;
|
||||
|
||||
$scope.fetchingURL = null;
|
||||
$scope._merchantData = $scope._domain = null;
|
||||
|
||||
$scope.lockAddress = false;
|
||||
$scope.lockAmount = false;
|
||||
|
||||
$scope._amount = $scope._address = null;
|
||||
|
||||
form.amount.$pristine = true;
|
||||
form.amount.$setViewValue('');
|
||||
form.amount.$render();
|
||||
|
||||
form.comment.$setViewValue('');
|
||||
form.comment.$render();
|
||||
form.$setPristine();
|
||||
};
|
||||
|
||||
var _onChanged = 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;
|
||||
}
|
||||
if (form.address) {
|
||||
form.address.$pristine = true;
|
||||
form.address.$setViewValue('');
|
||||
form.address.$render();
|
||||
}
|
||||
|
||||
value = value || $scope.address || '';
|
||||
var uri;
|
||||
if (!txStatus.notify(status))
|
||||
$scope.error = status;
|
||||
|
||||
$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;
|
||||
}
|
||||
$timeout(function() {
|
||||
$rootScope.$digest();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
if (value.indexOf('bitcoin:') === 0) {
|
||||
uri = new bitcore.BIP21(value);
|
||||
} else if (/^https?:\/\//.test(value)) {
|
||||
uri = {
|
||||
data : {
|
||||
merchant: value
|
||||
}
|
||||
var $oscope = $scope;
|
||||
$scope.openPPModal = function(merchantData) {
|
||||
var ModalInstanceCtrl = function($scope, $modalInstance) {
|
||||
$scope.md = merchantData;
|
||||
$scope.alternative = $oscope._alternative;
|
||||
$scope.alternativeIsoCode = $oscope.alternativeIsoCode;
|
||||
$scope.isRateAvailable = $oscope.isRateAvailable;
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
}
|
||||
|
||||
if (!uri || !uri.data.merchant) {
|
||||
if (uri && uri.address) {
|
||||
var amount = (uri.data && uri.data.amount) ? uri.data.amount * 100000000 * satToUnit : 0;
|
||||
var address = uri.address.data;
|
||||
if (amount && address) {
|
||||
$scope.isPayUri = true;
|
||||
}
|
||||
$timeout(function() {
|
||||
$scope.amount = amount;
|
||||
}, 1000);
|
||||
$scope.commentText = uri.data.message;
|
||||
$scope.address = address;
|
||||
}
|
||||
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);
|
||||
|
||||
// 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();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$scope.sendForm.address.$setViewValue('');
|
||||
$scope.sendForm.address.$render();
|
||||
}
|
||||
$scope.sendForm.address.$isValid = false;
|
||||
copay.logger.error(err);
|
||||
|
||||
$scope.error = 'Could not fetch payment request';
|
||||
|
||||
apply();
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
$modal.open({
|
||||
templateUrl: 'views/modals/paypro.html',
|
||||
windowClass: 'tiny',
|
||||
controller: ModalInstanceCtrl,
|
||||
});
|
||||
};
|
||||
|
||||
if ($rootScope.pendingPayment) {
|
||||
var value;
|
||||
var pp = $rootScope.pendingPayment;
|
||||
_onChanged(pp);
|
||||
}
|
||||
|
||||
$scope.setFromPayPro = function(uri) {
|
||||
var w = $rootScope.wallet;
|
||||
$scope.fetchingURL = uri;
|
||||
$scope.loading = true;
|
||||
|
||||
// Payment Protocol URI (BIP-72)
|
||||
w.fetchPaymentRequest({
|
||||
url: uri
|
||||
}, function(err, merchantData) {
|
||||
$scope.loading = false;
|
||||
$scope.fetchingURL = null;
|
||||
|
||||
if (err) {
|
||||
copay.logger.warn(err);
|
||||
if (err.toString().match('TIMEOUT')) {
|
||||
$scope.resetForm('Payment server timed out');
|
||||
} else {
|
||||
$scope.resetForm(err.toString());
|
||||
}
|
||||
} else {
|
||||
$scope._merchantData = merchantData;
|
||||
$scope._domain = merchantData.domain;
|
||||
$scope.setForm(null, merchantData.unitTotal);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setFromUri = function(uri) {
|
||||
var form = $scope.sendForm;
|
||||
|
||||
var parsed = new bitcore.BIP21(uri);
|
||||
if (!parsed.isValid() || !parsed.address.isValid()) {
|
||||
$scope.error = 'Invalid bitcoin URL';
|
||||
form.address.$isValid = false;
|
||||
return uri;
|
||||
};
|
||||
|
||||
var addr = parsed.address.toString();
|
||||
if (parsed.data.merchant)
|
||||
return $scope.setFromPayPro(parsed.data.merchant);
|
||||
|
||||
var amount = (parsed.data && parsed.data.amount) ?
|
||||
(parsed.data.amount * 100000000).toFixed(0) * satToUnit : 0;
|
||||
|
||||
$scope.setForm(addr, amount, parsed.data.message, true);
|
||||
return addr;
|
||||
};
|
||||
|
||||
$scope.onAddressChange = function(value) {
|
||||
$scope.error = $scope.success = null;
|
||||
if (!value) return '';
|
||||
|
||||
if (value.indexOf('bitcoin:') === 0) {
|
||||
return $scope.setFromUri(value);
|
||||
} else if (/^https?:\/\//.test(value)) {
|
||||
return $scope.setFromPayPro(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
$scope.openAddressBook = function() {
|
||||
var w = $rootScope.wallet;
|
||||
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;
|
||||
};
|
||||
|
||||
// TODO change to modal
|
||||
$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) {
|
||||
copay.logger.warn(e);
|
||||
errorMsg = e.message;
|
||||
}
|
||||
|
||||
$scope.close = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
},
|
||||
if (errorMsg) {
|
||||
$scope.error = errorMsg;
|
||||
} else {
|
||||
$scope.toggleForm();
|
||||
notification.success('Entry created', 'New addressbook entry created')
|
||||
}
|
||||
$rootScope.$digest();
|
||||
}, 1);
|
||||
return;
|
||||
};
|
||||
|
||||
$scope.close = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
modalInstance.result.then(function(addr) {
|
||||
$scope.address = addr;
|
||||
$scope.setForm(addr);
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,51 @@
|
|||
var bitcore = require('bitcore');
|
||||
|
||||
angular.module('copayApp.controllers').controller('walletForPaymentController', function($rootScope, $scope, $modal, identityService, go) {
|
||||
|
||||
$scope.selectWallet = function(cb) {
|
||||
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 = $rootScope.iden.listWallets();
|
||||
};
|
||||
|
||||
$scope.ok = function(w) {
|
||||
$modalInstance.close();
|
||||
return cb(w);
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.close();
|
||||
return cb();
|
||||
};
|
||||
};
|
||||
|
||||
$modal.open({
|
||||
templateUrl: 'views/modals/walletSelection.html',
|
||||
windowClass: 'tiny',
|
||||
controller: ModalInstanceCtrl,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// INIT: (not it a function, since there is no associated html)
|
||||
if (!$rootScope.pendingPayment) {
|
||||
go.walletHome();
|
||||
} else {
|
||||
$scope.selectWallet(function(w) {
|
||||
if (w) {
|
||||
identityService.setFocusedWallet(w);
|
||||
go.send();
|
||||
} else {
|
||||
go.walletHome();
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
|
@ -32,12 +32,6 @@ angular.module('copayApp.directives')
|
|||
link: function(scope, elem, attrs, ctrl) {
|
||||
var validator = function(value) {
|
||||
|
||||
// If we're setting the domain, ignore the change.
|
||||
if ($rootScope.merchant && $rootScope.merchant.domain && value === $rootScope.merchant.domain) {
|
||||
ctrl.$setValidity('validAddress', true);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Regular url
|
||||
if (/^https?:\/\//.test(value)) {
|
||||
ctrl.$setValidity('validAddress', true);
|
||||
|
@ -53,6 +47,11 @@ angular.module('copayApp.directives')
|
|||
return value;
|
||||
}
|
||||
|
||||
if (typeof value == 'undefined') {
|
||||
ctrl.$pristine = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Regular Address
|
||||
var a = new Address(value);
|
||||
ctrl.$setValidity('validAddress', a.isValid() && a.network().name === $rootScope.wallet.getNetworkName());
|
||||
|
@ -111,14 +110,11 @@ angular.module('copayApp.directives')
|
|||
var str_value = ('' + value).substring(sep_index + 1);
|
||||
if (sep_index > 0 && str_value.length > decimals) {
|
||||
ctrl.$setValidity('validAmount', false);
|
||||
scope.notValidAmount = true;
|
||||
} else {
|
||||
ctrl.$setValidity('validAmount', true);
|
||||
scope.notValidAmount = null;
|
||||
}
|
||||
} else {
|
||||
ctrl.$setValidity('validAmount', false);
|
||||
scope.notValidAmount = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -509,6 +509,9 @@ Identity.prototype.bindWallet = function(w) {
|
|||
w.on('publicKeyRingUpdated', function() {
|
||||
Identity.storeWalletDebounced(self, w);
|
||||
});
|
||||
w.on('ready', function() {
|
||||
Identity.storeWalletDebounced(self, w);
|
||||
});
|
||||
|
||||
this.emitAndKeepAlive('newWallet', w.getId());
|
||||
};
|
||||
|
|
|
@ -1747,9 +1747,11 @@ Wallet.prototype._addOutputsToMerchantData = function(merchantData) {
|
|||
|
||||
// If user is granted the privilege of choosing
|
||||
// their own amount, add it to the tx.
|
||||
if (merchantData.total === 0 && options.amount) {
|
||||
merchant.outs[0].amountSatStr = merchantData.total = outions.amount;
|
||||
if (merchantData.total == "0" && options.amount) {
|
||||
merchant.outs[0].amountSatStr = merchantData.total = options.amount;
|
||||
}
|
||||
|
||||
merchantData.unitTotal = merchantData.total ? (+merchantData.total / this.settings.unitToSatoshi) + '' : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1793,6 +1795,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,9 +1829,13 @@ 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,
|
||||
expirationDate: expires ? new Date(expires * 1000) : null,
|
||||
};
|
||||
|
||||
this._addOutputsToMerchantData(merchantData, options.amount);
|
||||
|
||||
return merchantData;
|
||||
};
|
||||
|
||||
|
@ -2173,9 +2180,21 @@ Wallet.prototype.spend = function(opts, cb) {
|
|||
var toAddress = opts.toAddress;
|
||||
var amountSat = opts.amountSat;
|
||||
var comment = opts.comment;
|
||||
var url = opts.url;
|
||||
var merchantData = opts.merchantData;
|
||||
|
||||
|
||||
// PayPro? With given merchant data
|
||||
if (opts.merchantData && !opts.toAddress) {
|
||||
if (!merchantData.outs[0].address)
|
||||
return cb(new Error('BADPAYPRO'));
|
||||
|
||||
opts.toAddress = merchantData.outs[0].address;
|
||||
opts.amountSat = parseInt(merchantData.outs[0].amountSatStr);
|
||||
return self.spend(opts, cb);
|
||||
}
|
||||
|
||||
// PayPro? Fetch payment data and recurse
|
||||
var url = opts.url;
|
||||
if (url && !opts.merchantData) {
|
||||
return self.fetchPaymentRequest({
|
||||
url: url,
|
||||
|
@ -2184,8 +2203,6 @@ Wallet.prototype.spend = function(opts, cb) {
|
|||
}, function(err, merchantData) {
|
||||
if (err) return cb(err);
|
||||
opts.merchantData = merchantData;
|
||||
opts.toAddress = merchantData.outs[0].address;
|
||||
opts.amountSat = parseInt(merchantData.outs[0].amountSatStr);
|
||||
return self.spend(opts, cb);
|
||||
});
|
||||
}
|
||||
|
@ -2203,13 +2220,13 @@ Wallet.prototype.spend = function(opts, cb) {
|
|||
try {
|
||||
txp = self._createTxProposal(toAddress,
|
||||
amountSat, comment, safeUnspent, opts.builderOpts);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
return cb(e);
|
||||
}
|
||||
|
||||
if (opts.merchantData) {
|
||||
txp.addMerchantData(opts.merchantData);
|
||||
if (opts.merchantData) {
|
||||
txp.addMerchantData(opts.merchantData);
|
||||
}
|
||||
} catch (e) {
|
||||
log.warn(e);
|
||||
return cb(e);
|
||||
}
|
||||
|
||||
var ntxid = self.txProposals.add(txp);
|
||||
|
@ -2546,7 +2563,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) {
|
||||
|
@ -2669,7 +2686,6 @@ Wallet.prototype.getTransactionHistory = function(opts, cb) {
|
|||
tx.sentTs = proposal.sentTs;
|
||||
tx.merchant = proposal.merchant;
|
||||
tx.peerActions = proposal.peerActions;
|
||||
tx.merchant = proposal.merchant;
|
||||
tx.paymentAckMemo = proposal.paymentAckMemo;
|
||||
tx.actionList = self._getActionList(proposal);
|
||||
}
|
||||
|
|
17
js/routes.js
17
js/routes.js
|
@ -22,11 +22,14 @@ angular
|
|||
template: " ", // just fire controller
|
||||
controller: 'EmailConfirmationController',
|
||||
})
|
||||
.when('/uri-payment/:data', {
|
||||
templateUrl: 'views/uri-payment.html'
|
||||
})
|
||||
.when('/paymentIntent', {
|
||||
templateUrl: 'views/paymentIntent.html',
|
||||
// Payment intents come here.
|
||||
.when('/uri-payment/:data', {
|
||||
template: " ", // just fire controller
|
||||
controller: 'paymentUriController',
|
||||
})
|
||||
.when('/selectWalletForPayment', {
|
||||
template: " ", // just fire controller
|
||||
controller: 'walletForPaymentController',
|
||||
logged: true
|
||||
})
|
||||
.when('/join', {
|
||||
|
@ -124,6 +127,7 @@ angular
|
|||
}
|
||||
|
||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||
|
||||
if (!ls || ls.length < 1) {
|
||||
$location.path('unsupported');
|
||||
} else {
|
||||
|
@ -131,7 +135,8 @@ angular
|
|||
$idle.unwatch();
|
||||
$location.path('/');
|
||||
}
|
||||
if ($rootScope.wallet && !$rootScope.wallet.isComplete() && next.walletShouldBeComplete) {
|
||||
if ($rootScope.wallet && !$rootScope.wallet.isComplete()
|
||||
&& next.walletShouldBeComplete) {
|
||||
$location.path('/copayers');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,33 @@ angular.module('copayApp.services').factory('go', function($window, $location) {
|
|||
toggleSidebar(invert);
|
||||
};
|
||||
|
||||
root.walletHome = function() {
|
||||
var w = $rootScope.wallet;
|
||||
preconditions.checkState(w);
|
||||
$rootScope.starting = false;
|
||||
|
||||
if (!w.isComplete()) {
|
||||
root.path('copayers');
|
||||
} else {
|
||||
if ($rootScope.pendingPayment) {
|
||||
root.path('selectWalletForPayment');
|
||||
} else {
|
||||
root.path('homeWallet');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
root.home = function() {
|
||||
if ($rootScope.iden)
|
||||
root.walletHome();
|
||||
else
|
||||
root.path('/');
|
||||
};
|
||||
|
||||
|
||||
root.send = function() {
|
||||
$location.path('send');
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('txStatus', function($modal) {
|
||||
var root = {};
|
||||
|
||||
root.notify = function(status) {
|
||||
var msg;
|
||||
if (status == copay.Wallet.TX_BROADCASTED)
|
||||
msg = 'Transaction broadcasted!';
|
||||
else if (status == copay.Wallet.TX_PROPOSAL_SENT)
|
||||
msg = 'Transaction proposal created';
|
||||
else if (status == copay.Wallet.TX_SIGNED)
|
||||
msg = 'Transaction proposal was signed';
|
||||
else if (status == copay.Wallet.TX_SIGNED_AND_BROADCASTED)
|
||||
msg = 'Transaction signed and broadcasted!';
|
||||
else if (status == 'txRejected')
|
||||
msg = 'Transaction was rejected!';
|
||||
|
||||
if (msg)
|
||||
root.openModal(msg);
|
||||
return msg ? true : false;
|
||||
};
|
||||
|
||||
root.openModal = function(statusStr) {
|
||||
var ModalInstanceCtrl = function($scope, $modalInstance) {
|
||||
$scope.statusStr = statusStr;
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
};
|
||||
$modal.open({
|
||||
templateUrl: 'views/modals/tx-status.html',
|
||||
windowClass: 'tiny',
|
||||
controller: ModalInstanceCtrl,
|
||||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
|
@ -2,7 +2,7 @@
|
|||
"name": "copay",
|
||||
"description": "A multisignature wallet",
|
||||
"author": "BitPay",
|
||||
"version": "0.8.3",
|
||||
"version": "0.8.4",
|
||||
"keywords": [
|
||||
"wallet",
|
||||
"copay",
|
||||
|
|
|
@ -26,7 +26,7 @@ var inherits = function(ctor, superCtor) {
|
|||
|
||||
inherits(FakeSocket, EventEmitter);
|
||||
|
||||
FakeSocket.prototype.removeEventListener = function() {
|
||||
FakeSocket.prototype.removeListener = function() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,16 +195,16 @@ describe("Unit: Controllers", function() {
|
|||
scope.model = {
|
||||
newaddress: null,
|
||||
newlabel: null,
|
||||
address: null,
|
||||
amount: null
|
||||
_address: null,
|
||||
_amount: null
|
||||
};
|
||||
$compile(element)(scope);
|
||||
|
||||
var element2 = angular.element(
|
||||
'<form name="form2">' +
|
||||
'<input type="text" id="address" name="address" ng-model="address" valid-address required>' +
|
||||
'<input type="number" id="amount" name="amount" ng-model="amount" min="1" max="10000000000" required>' +
|
||||
'<input type="number" id="alternative" name="alternative" ng-model="alternative">' +
|
||||
'<input type="text" id="address" name="address" ng-model="_address" valid-address required>' +
|
||||
'<input type="number" id="amount" name="amount" ng-model="_amount" min="1" max="10000000000" required>' +
|
||||
'<input type="number" id="alternative" name="alternative" ng-model="_alternative">' +
|
||||
'<textarea id="comment" name="comment" ng-model="commentText" ng-maxlength="100"></textarea>' +
|
||||
'</form>'
|
||||
);
|
||||
|
@ -213,7 +213,7 @@ describe("Unit: Controllers", function() {
|
|||
$scope: scope,
|
||||
$modal: {},
|
||||
});
|
||||
|
||||
scope.init();
|
||||
scope.$digest();
|
||||
form = scope.form;
|
||||
sendForm = scope.form2;
|
||||
|
@ -221,11 +221,11 @@ describe("Unit: Controllers", function() {
|
|||
}));
|
||||
|
||||
it('should have a SendController controller', function() {
|
||||
expect(scope.loading).equal(false);
|
||||
should.exist(scope.submitForm);
|
||||
});
|
||||
|
||||
it('should have a title', function() {
|
||||
expect(scope.title).equal('Create Transaction Proposal');
|
||||
expect(scope.title);
|
||||
});
|
||||
|
||||
it('should validate address with network', function() {
|
||||
|
@ -302,7 +302,8 @@ describe("Unit: Controllers", function() {
|
|||
scope.rateService.whenAvailable(function() {
|
||||
sendForm.amount.$setViewValue(1e6);
|
||||
scope.$digest();
|
||||
expect(scope.alternative).to.equal(2);
|
||||
expect(scope._amount).to.equal(1e6);
|
||||
expect(scope.__alternative).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -310,7 +311,8 @@ describe("Unit: Controllers", function() {
|
|||
scope.rateService.whenAvailable(function() {
|
||||
sendForm.alternative.$setViewValue(2);
|
||||
scope.$digest();
|
||||
expect(scope.amount).to.equal(1e6);
|
||||
expect(scope.__alternative).to.equal(2);
|
||||
expect(scope._amount).to.equal(1e6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -517,7 +519,7 @@ describe("Unit: Controllers", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('UriPayment Controller', function() {
|
||||
describe('paymentUriController Controller', function() {
|
||||
var what;
|
||||
beforeEach(inject(function($controller, $rootScope, $location) {
|
||||
scope = $rootScope.$new();
|
||||
|
@ -528,7 +530,7 @@ describe("Unit: Controllers", function() {
|
|||
amount: 0.1,
|
||||
message: "a bitcoin donation"
|
||||
};
|
||||
what = $controller('UriPaymentController', {
|
||||
what = $controller('paymentUriController', {
|
||||
$scope: scope,
|
||||
$routeParams: routeParams,
|
||||
$location: {
|
||||
|
@ -546,9 +548,7 @@ describe("Unit: Controllers", function() {
|
|||
it('should parse url correctly', function() {
|
||||
should.exist(what);
|
||||
should.exist(scope.pendingPayment);
|
||||
scope.pendingPayment.address.data.should.equal('19mP9FKrXqL46Si58pHdhGKow88SUPy1V8');
|
||||
scope.pendingPayment.data.amount.should.equal(0.1);
|
||||
scope.pendingPayment.data.message.should.equal('a bitcoin donation');
|
||||
scope.pendingPayment.should.equal('bitcoin:19mP9FKrXqL46Si58pHdhGKow88SUPy1V8?amount=0.1&message=a bitcoin donation');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -94,9 +94,6 @@ describe("Unit: Testing Directives", function() {
|
|||
form.amount.$setViewValue(800);
|
||||
expect(form.amount.$invalid).to.equal(false);
|
||||
form.amount.$setViewValue(900);
|
||||
expect($scope.notValidAmount).to.equal(null);
|
||||
form.amount.$setViewValue(0.44);
|
||||
expect($scope.notValidAmount).to.equal(null);
|
||||
|
||||
});
|
||||
|
||||
|
@ -105,8 +102,6 @@ describe("Unit: Testing Directives", function() {
|
|||
expect(form.amount.$invalid).to.equal(true);
|
||||
form.amount.$setViewValue(999999999999);
|
||||
expect(form.amount.$invalid).to.equal(true);
|
||||
form.amount.$setViewValue(0.333);
|
||||
expect($scope.notValidAmount).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -134,19 +129,15 @@ describe("Unit: Testing Directives", function() {
|
|||
|
||||
it('should validate', function() {
|
||||
form.amount.$setViewValue(0.01);
|
||||
expect($scope.notValidAmount).to.equal(null);
|
||||
expect(form.amount.$invalid).to.equal(false);
|
||||
form.amount.$setViewValue(0.039);
|
||||
expect($scope.notValidAmount).to.equal(null);
|
||||
expect(form.amount.$invalid).to.equal(false);
|
||||
form.amount.$setViewValue(100292.039);
|
||||
expect($scope.notValidAmount).to.equal(null);
|
||||
expect(form.amount.$invalid).to.equal(false);
|
||||
});
|
||||
|
||||
it('should not validate', function() {
|
||||
form.amount.$setViewValue(0.039998888888888);
|
||||
expect($scope.notValidAmount).to.equal(true);
|
||||
expect(form.amount.$invalid).to.equal(true);
|
||||
form.amount.$setViewValue(0);
|
||||
expect(form.amount.$invalid).to.equal(true);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<div ng-controller="CopayersController">
|
||||
<div ng-if='$root.wallet && $root.wallet.isComplete()' ng-init="goToWallet()"></div>
|
||||
|
||||
<div ng-controller="CopayersController" ng-init="init()">
|
||||
<div class="row hide-for-large-up">
|
||||
<div class="medium-12 small-12 columns">
|
||||
<h1 translate>
|
||||
|
@ -14,6 +12,13 @@
|
|||
<div class="panel oh">
|
||||
<h2 class="line-b">
|
||||
Share this secret with your other copayers
|
||||
<div class="right size-10">
|
||||
<span ng-if="!$root.wallet.isShared()">Personal Wallet</span>
|
||||
<span ng-if="$root.wallet.isShared()">
|
||||
Multisignature wallet [{{$root.wallet.requiredCopayers}} of {{$root.wallet.totalCopayers}} ]
|
||||
</span>
|
||||
<span ng-if="$root.wallet.isTestnet()"> in TESTNET</span>
|
||||
</div>
|
||||
</h2>
|
||||
<div class="text-center">
|
||||
<qrcode size="250" data="{{secret}}"></qrcode>
|
||||
|
@ -24,7 +29,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="panel oh">
|
||||
<div ng-include="'views/includes/copayer.html'"></div>
|
||||
<div ng-include="'views/includes/copayers.html'"></div>
|
||||
<div class="copay-box" ng-if="!$root.wallet.isComplete()">
|
||||
<span ng-include="'views/includes/photo.html'"></span>
|
||||
<p class="size-12 text-white text-light m0">
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
</div>
|
||||
<div class="row" ng-if="blockchain_txs[0].txid">
|
||||
<div class="large-12 columns">
|
||||
<div class="panel" ng-repeat="btx in blockchain_txs | orderBy:'-ts'">
|
||||
<div class="row size-14" ng-click="openTxModal(btx)">
|
||||
<div class="panel" ng-repeat="btx in blockchain_txs | orderBy:'-ts'" ng-click="openTxModal(btx)">
|
||||
<div class="row size-14">
|
||||
|
||||
<div class="large-2 medium-3 small-4 columns">
|
||||
<div class="tx-date oh">
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
</button>
|
||||
</form>
|
||||
|
||||
<div ng-if="usingLocalStorage" class="text-gray size-12">
|
||||
<div ng-if="usingLocalStorage" class="text-gray size-12 m10v">
|
||||
* Using this device storage. Change to cloud storage on 'settings'.
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="home-wallet" ng-controller="HomeWalletController" ng-init="init()">
|
||||
<div class="home-wallet" ng-controller="HomeWalletController" ng-init="initHome()">
|
||||
<div class="row hide-for-large-up">
|
||||
<div class="medium-12 small-12 columns">
|
||||
<h1 translate>Home</h1>
|
||||
|
@ -63,7 +63,7 @@
|
|||
<div class="large-12 columns">
|
||||
<div class="panel oh">
|
||||
<h2 class="line-b" translate>Copayers</h2>
|
||||
<div ng-include="'views/includes/copayer.html'"></div>
|
||||
<div ng-include="'views/includes/copayers.html'"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div ng-controller="CopayersController">
|
||||
<div class="copay-box" ng-repeat="copayer in copayersList()">
|
||||
<div>
|
||||
<div class="copay-box" ng-repeat="copayer in copayers">
|
||||
<div class="photo-container">
|
||||
<img gravatar-src="'{{copayer.nick}}'" gravatar-size="35">
|
||||
</div>
|
|
@ -2,7 +2,7 @@
|
|||
<h1>
|
||||
{{$root.title}}
|
||||
<small ng-if="$root.wallet">
|
||||
<a class="text-gray" ng-click="refresh()" ng-if="!$root.updatingBalance">
|
||||
<a class="text-gray" ng-click="refresh()" ng-if="$root.wallet.isComplete() && !$root.updatingBalance">
|
||||
<i class="fi-refresh"></i>
|
||||
</a>
|
||||
<span ng-if="$root.updatingBalance">
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
<div class="last-transactions-header row collapse" ng-init="txIndex = $index">
|
||||
<div class="last-transactions-header row collapse" ng-init="txIndex = $index" ng-click="openTxModal(tx)">
|
||||
<div class="large-9 small-7 columns size-14">
|
||||
<div ng-show="tx.comment">
|
||||
<i class="fi-comment-quotes size-18 vm"></i>
|
||||
|
@ -22,25 +21,21 @@
|
|||
<div class="large-2 medium-2 small-1 columns text-center">
|
||||
<i class="fi-arrow-right"></i>
|
||||
</div>
|
||||
<div class="large-5 medium-5 small-5 columns ellipsis size-12">
|
||||
<contact address="{{out.address}}" tooltip-popup-delay="500" tooltip tooltip-placement="right" />
|
||||
<div class="large-5 medium m0-5 small-5 columns ellipsis size-12">
|
||||
<div ng-if="tx.merchant">
|
||||
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock color-greeni"></i> {{tx.merchant.domain}}</span>
|
||||
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock color-yellowi"></i> {{tx.merchant.domain}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<contact address="{{out.address}}" tooltip-popup-delay="500" tooltip tooltip-placement="right" ng-hide="tx.merchant" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="m10t" ng-show="!!tx.merchant">
|
||||
<div class="send-note">
|
||||
<span><b>{{tx.merchant.pr.pd.memo}}</b></span> <br>
|
||||
<span>Expires {{tx.merchant.pr.pd.expires * 1000 | amTimeAgo }} </span>
|
||||
<span ng-show="tx.merchant.domain">[{{tx.merchant.domain}}]</span>
|
||||
<span ng-show="!!tx.merchant.pr.ca"><i class="icon-locked size-14"></i> {{tx.merchant.pr.ca}}</span>
|
||||
<span ng-show="!tx.merchant.pr.ca" style="color:red;weight:bold;"><i class="fi-unlock"></i> Untrusted</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-b"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="last-transactions-footer">
|
||||
<div class="row collapse">
|
||||
<div class="large-6 medium-12 small-12 columns" ng-show="!tx.sentTs">
|
||||
<div class="small-12 columns" ng-show="!tx.sentTs">
|
||||
<div ng-show="tx.signedBy[myId]">
|
||||
<button class="secondary left m10r tiny m0 radius" ng-disabled="true"> <i class="fi-check icon-sign check"></i>
|
||||
<span translate>Signed by me</span>
|
||||
|
@ -52,64 +47,45 @@
|
|||
</button>
|
||||
</div>
|
||||
<div ng-show="!tx.signedBy[myId] && !tx.rejectedBy[myId]">
|
||||
<div class="hide-for-small-only">
|
||||
<button class="primary tiny m0 m15r" ng-click="sign(tx.ntxid)" ng-disabled="loading">
|
||||
<i class="fi-check icon-sign check"></i> <span translate>Sign</span>
|
||||
</button>
|
||||
<button class="warning tiny m0" ng-click="reject(tx.ntxid)" ng-disabled="loading">
|
||||
<i class="fi-x icon-sign x" ></i> <span translate>Reject</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="show-for-small-only row">
|
||||
<button class="primary tiny small-5 columns m10b" ng-click="sign(tx.ntxid)" ng-disabled="loading">
|
||||
<i class="fi-check icon-sign check"></i> <span translate>Sign</span>
|
||||
</button>
|
||||
<button class="warning tiny small-5 columns m10b" ng-click="reject(tx.ntxid)" ng-disabled="loading">
|
||||
<i class="fi-x icon-sign x" ></i> <span translate>Reject</span>
|
||||
</button>
|
||||
<div class="row">
|
||||
<div class="large-6 medium-6 small-6 columns text-left">
|
||||
<button class="button warning tiny m0" ng-click="reject(tx.ntxid)" ng-disabled="loading">
|
||||
<i class="fi-x icon-sign x"></i> <span translate>Reject</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns text-right">
|
||||
<button class="button primary tiny m0" ng-click="sign(tx.ntxid)" ng-disabled="loading">
|
||||
<i class="fi-check icon-sign check"></i> <span translate>Sign</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="!tx.missingSignatures && !tx.sentTs">
|
||||
<button class="primary tiny m0" ng-click="send(tx.ntxid)" ng-disabled="loading"> <i class="fi-upload-cloud"></i>
|
||||
<button class="primary tiny m0" ng-click="send(tx.ntxid)" ng-disabled="loading"> <i class="fi-upload-cloud"></i>
|
||||
<span translate>Broadcast Transaction</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="large-6 columns small text-gray show-for-large-up text-right">
|
||||
<div>
|
||||
<strong translate>Fee</strong>: {{tx.fee}} {{$root.wallet.settings.unitName}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<a class="missing-copayers" ng-click="tx.showDetails = !tx.showDetails">
|
||||
<div class="row collapse">
|
||||
<div class="small-12 small text-gray text-center">
|
||||
<span ng-click="tx.showDetails = !tx.showDetails">
|
||||
<span ng-show="!tx.finallyRejected && tx.missingSignatures==1">
|
||||
<i class="fi-torso"></i>
|
||||
One signature missing
|
||||
</span>
|
||||
<span ng-show="!tx.finallyRejected && tx.missingSignatures>1">
|
||||
<span ng-show="!tx.finallyRejected && tx.missingSignatures>1">
|
||||
<i class="icon-people"></i>
|
||||
{{tx.missingSignatures}} signatures missing
|
||||
</span>
|
||||
<span ng-show="!tx.finallyRejected && tx.missingSignatures==0">
|
||||
<span ng-show="!tx.finallyRejected && tx.missingSignatures==0">
|
||||
Copayers
|
||||
</span>
|
||||
<i ng-class="{'icon-arrow-up2':tx.showDetails, 'icon-arrow-down2':!tx.showDetails}"></i>
|
||||
</a>
|
||||
|
||||
<ul class="tx-copayers" ng-show="tx.showDetails">
|
||||
<li ng-repeat="c in tx.actionList" ng-class="{'bottom-line-copayers':!$last}">
|
||||
<span>
|
||||
<i ng-if="c.actions.rejected" class="fi-x icon-sign x"></i>
|
||||
<i ng-if="c.actions.sign" class="fi-check icon-sign check"></i>
|
||||
<i ng-if="!c.actions.sign && !c.actions.rejected && tx.missingSignatures" class="m10r fi-loop icon-rotate"></i>
|
||||
</span>
|
||||
<span>
|
||||
<i ng-if="c.actions.create" class="fi-crown icon-status icon-active m10r"></i>
|
||||
</span>
|
||||
<span>{{c.cId === $root.wallet.getMyCopayerId() ? 'Me' : $root.wallet.publicKeyRing.nicknameForCopayer(c.cId)}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<a class="close-reveal-modal" ng-click="cancel()">×</a>
|
||||
|
||||
<div class="size-14">
|
||||
<h1 class="m30v">Payment Request</h1>
|
||||
|
||||
<p>
|
||||
<b translate>Signature:</b> {{md.domain}}
|
||||
<span ng-show="md.pr.ca"><i class="fi-lock color-greeni"></i> {{md.pr.ca}}</span>
|
||||
<span ng-show="!md.pr.ca"><i class="fi-unlock color-yellowi"></i> Untrusted</span>
|
||||
<p>
|
||||
<b translate>Merchant Message:</b>
|
||||
<br>
|
||||
{{md.pr.pd.memo || address}}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b translate>Amount:</b>
|
||||
{{md.unitTotal}} {{$root.wallet.settings.unitName}}
|
||||
<span class="text-gray" ng-if="isRateAvailable">
|
||||
{{ alternative }} {{ alternativeIsoCode }}
|
||||
</span>
|
||||
|
||||
<div ng-if="md.expirationDate" class="m10v">
|
||||
<b>Expires</b>: {{md.expirationDate | amTimeAgo }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
</div>
|
||||
<div class="line-b m10t"></div>
|
||||
<h1 class="m30v">Transaction Details</h1>
|
||||
<div class="ellipsis"> <b>ID:</b> <span class="text-gray"> {{btx.txid}} </span></div>
|
||||
<div ng-if="btx.ts" class="m10v">
|
||||
<time><b>{{btx.ts | amTimeAgo}}</b></time>
|
||||
:
|
||||
<time> <span class="text-gray">{{btx.ts | amCalendar}}</span></time>
|
||||
<div class="ellipsis" ng-if="btx.txid"> <b>ID:</b> <span class="text-gray"> {{btx.txid}} </span></div>
|
||||
<div ng-if="btx.ts || btx.createdTs " class="m10v">
|
||||
<time> <span>{{ (btx.ts || btx.createdTs ) | amCalendar}}</span></time>
|
||||
|
||||
[<time>{{ (btx.ts || btx.createdTs ) | amTimeAgo}}</time>]
|
||||
</div>
|
||||
|
||||
<div class="m10v">
|
||||
|
@ -51,15 +51,19 @@
|
|||
<div ng-if="btx.addressTo" class="m10v">
|
||||
<span class="ellipsis">
|
||||
<b>To:</b>
|
||||
<span class="text-gray"> {{btx.labelTo || btx.addressTo}}</span>
|
||||
<span ng-if="btx.merchant">
|
||||
<span ng-show="btx.merchant.pr.ca"><i class="fi-lock color-greeni"></i> {{btx.merchant.domain}}</span>
|
||||
<span ng-show="!btx.merchant.pr.ca"><i class="fi-unlock color-yellowi"></i> {{btx.merchant.domain}}</span>
|
||||
</span>
|
||||
|
||||
<span ng-if="!btx.merchant">
|
||||
<span class="text-gray"> {{btx.labelTo || btx.addressTo}}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="!!btx.merchant" class="m10v">
|
||||
Payment Protocol Information:
|
||||
<br>{{btx.merchant.pr.pd.memo}}</b>
|
||||
<br>{{btx.paymentAckMemo}}
|
||||
<span ng-show="tx.merchant.domain">[{{btx.merchant.domain}}]</span>
|
||||
<div ng-if="btx.merchant" class="m10v">
|
||||
{{btx.merchant.pr.pd.memo}}
|
||||
</div>
|
||||
|
||||
<div ng-if="btx.actionList[0]" class="m10v">
|
||||
|
@ -79,12 +83,11 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="m10t oh">
|
||||
<div class="m10t oh" ng-if="btx.txid">
|
||||
<a class="right button-setup"
|
||||
ng-click="openExternalLink('http://' + getShortNetworkName() + '.insight.is/tx/' + btx.txid)">
|
||||
See it on the blockchain <i class="icon-arrow-right2 vm"></i>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
<div class="size-14">
|
||||
|
||||
<div class="text-center size-72 m10v">
|
||||
<div class="text-primary">
|
||||
<i class="fi-check"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-center m10v">
|
||||
{{statusStr}}
|
||||
</div>
|
||||
<div class="text-center m10v">
|
||||
<a class="button primary" ng-click="cancel()">OKAY</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
<a class="close-reveal-modal" ng-click="cancel()">×</a>
|
||||
|
||||
<h1 class="m30v">Transaction Proposal Details</h1>
|
||||
|
||||
<div class="row" ng-repeat="out in tx.outs">
|
||||
<div class="large-5 medium-5 small-6 columns size-14">
|
||||
<b>{{out.value}} {{$root.wallet.settings.unitName}}</b>
|
||||
<span ng-show="out.alternativeAmount" class="alt-currency gray">
|
||||
{{out.alternativeAmount}} {{out.alternativeIsoCode}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="large-2 medium-2 small-1 columns text-center">
|
||||
<i class="fi-arrow-right"></i>
|
||||
</div>
|
||||
<div class="large-5 medium m0-5 small-5 columns ellipsis size-12">
|
||||
<div ng-if="tx.merchant">
|
||||
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock color-greeni"></i> {{tx.merchant.domain}}</span>
|
||||
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock color-yellowi"></i> {{tx.merchant.domain}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<contact address="{{out.address}}" tooltip-popup-delay="500" tooltip tooltip-placement="right" ng-hide="tx.merchant" />
|
||||
</div>
|
||||
|
||||
<div class="text-light size-14">{{tx.comment}}</div>
|
||||
|
||||
<div class="line-b m10t"></div>
|
||||
<div ng-if="tx.createdTs " class="m10v size-14">
|
||||
<time> <span>{{ tx.createdTs | amCalendar}}</span></time>
|
||||
|
||||
[<time>{{ tx.createdTs | amTimeAgo}}</time>]
|
||||
</div>
|
||||
|
||||
<div ng-if="tx.addressTo" class="m10v">
|
||||
<span class="ellipsis">
|
||||
<b>To:</b>
|
||||
<span ng-if="tx.merchant">
|
||||
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock color-greeni"></i> {{tx.merchant.domain}}</span>
|
||||
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock color-yellowi"></i> {{tx.merchant.domain}}</span>
|
||||
</span>
|
||||
|
||||
<span ng-if="!tx.merchant">
|
||||
<span class="text-gray"> {{tx.labelTo || tx.addressTo}}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="tx.merchant" class="size-12 m10v">
|
||||
{{tx.merchant.pr.pd.memo}}
|
||||
|
||||
<div ng-if="tx.merchant.expirationDate" class="m10v">
|
||||
<b>Expires</b>: {{tx.merchant.expirationDate | amTimeAgo }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div ng-if="tx.actionList[0]" class="m10v">
|
||||
<b>Copayers Signatures</b>
|
||||
<ul class="tx-copayers m10t" ng-if="tx.actionList[0]">
|
||||
<li ng-repeat="c in tx.actionList" ng-class="{'bottom-line-copayers':!$last}">
|
||||
<span>
|
||||
<i ng-if="c.actions.rejected" class="fi-x icon-sign x"></i>
|
||||
<i ng-if="c.actions.sign" class="fi-check icon-sign check"></i>
|
||||
<i ng-if="!c.actions.sign && !c.actions.rejected && tx.missingSignatures" class="m10r fi-loop icon-rotate"></i>
|
||||
</span>
|
||||
<span>
|
||||
<i ng-if="c.actions.create" class="fi-crown icon-status icon-active m10r"></i>
|
||||
</span>
|
||||
<span>{{c.cId === $root.wallet.getMyCopayerId() ? 'Me' : $root.wallet.publicKeyRing.nicknameForCopayer(c.cId)}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<a class="close-reveal-modal" ng-click="cancel()">×</a>
|
||||
|
||||
<h3 ng-init="setWallets()">Select a wallet to make the payment</h3>
|
||||
<span ng-show="!wallets[0]">Loading...</span>
|
||||
<ul class="w-popup-menu" ng-show="wallets[0]" ng-class="{'large':wallets.length > 4, 'medium':wallets.length > 2 && wallets.length < 5}">
|
||||
<li data-ng-repeat="item in wallets track by $index" class="nav-item" ng-click="ok(item)" ng-show="+item.balanceInfo.totalBalanceBTC > 0">
|
||||
<div class="w-popup-icon">
|
||||
<div class="avatar-wallet">{{(item.name || item.id) | limitTo: 1}}</div>
|
||||
</div>
|
||||
<div class="w-popup-content">
|
||||
<div class="">
|
||||
<a class="size-12 wallet-item">
|
||||
<div class="">
|
||||
<div class="w-popup-main">[ {{item.requiredCopayers}} of {{item.totalCopayers}} ]</div>
|
||||
<div class="w-popup-sub size-18">{{item.name || item.id}}</div>
|
||||
</div>
|
||||
<div class="w-popup-sub">
|
||||
<span ng-if="item.balanceInfo.updatingBalance"><i class="fi-bitcoin-circle icon-rotate spinner"></i></span>
|
||||
<div ng-if="!item.balanceInfo.updatingBalance" data-options="disable_for_touch:true">
|
||||
<b class="m5r size-12">{{item.balanceInfo.totalBalance || 0}} {{item.settings.unitName}}</b>
|
||||
<span class="alt-currency size-10">{{item.balanceInfo.totalBalanceAlternative}} {{item.balanceInfo.alternativeIsoCode}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
<div ng-controller="PaymentIntentController" ng-init="open()">
|
||||
<script type="text/ng-template" id="myModalContent.html">
|
||||
<h3>Select a wallet to make the payment</h3>
|
||||
<span ng-show="loading">Loading...</span>
|
||||
<ul class="w-popup-menu" ng-show="wallets[0]"
|
||||
ng-class="{'large':wallets.length > 4, 'medium':wallets.length > 2 && wallets.length < 5}">
|
||||
<li data-ng-repeat="item in wallets track by $index" class="nav-item" ng-click="ok(item)">
|
||||
<div class="w-popup-icon">
|
||||
<div class="avatar-wallet">{{(item.name || item.id) | limitTo: 1}}</div>
|
||||
</div>
|
||||
<div class="w-popup-content">
|
||||
<div class="">
|
||||
<a class="size-12 wallet-item">
|
||||
<div class="">
|
||||
<div class="w-popup-main">[ {{item.requiredCopayers}} of {{item.totalCopayers}} ]</div>
|
||||
<div class="w-popup-sub size-18">{{item.name || item.id}}</div>
|
||||
</div>
|
||||
<div class="w-popup-sub">
|
||||
<span ng-if="item.balanceInfo.updatingBalance"><i class="fi-bitcoin-circle icon-rotate spinner"></i></span>
|
||||
<div ng-if="!item.balanceInfo.updatingBalance" data-options="disable_for_touch:true">
|
||||
<b class="m5r size-12">{{item.balanceInfo.totalBalance || 0}} {{item.settings.unitName}}</b>
|
||||
<span class="alt-currency size-10">{{item.balanceInfo.totalBalanceAlternative}} {{item.balanceInfo.alternativeIsoCode}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="close-reveal-modal" ng-click="cancel()">×</a>
|
||||
</script>
|
||||
</div>
|
310
views/send.html
310
views/send.html
|
@ -1,55 +1,54 @@
|
|||
<div class="send" ng-controller="SendController" ng-init="init()">
|
||||
<div class="send" ng-controller="SendController" ng-init="init()">
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 medium-12 small-12 columns">
|
||||
<h1 class="hide-for-large-up">{{$root.title}}</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="large-12 medium-12 small-12 columns">
|
||||
<h1 class="hide-for-large-up">{{$root.title}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<form name="sendForm" ng-submit="submitForm(sendForm)" novalidate>
|
||||
<div class="panel">
|
||||
|
||||
<div class="box-notification" ng-show="error">
|
||||
<div class="box-icon error">
|
||||
<i class="fi-x size-24"></i>
|
||||
</div>
|
||||
<span class="text-warning size-14">
|
||||
{{error|translate}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="box-notification" ng-show="success">
|
||||
<div class="box-icon success">
|
||||
<i class="fi-check size-24"></i>
|
||||
</div>
|
||||
<span class="text-success size-14">
|
||||
{{success|translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<form name="sendForm" ng-submit="submitForm(sendForm)" novalidate>
|
||||
<div class="panel">
|
||||
<div class="box-notification" ng-show="error">
|
||||
<div class="box-icon error">
|
||||
<i class="fi-x size-24"></i>
|
||||
</div>
|
||||
<span class="text-warning size-14">
|
||||
{{error|translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="box-notification" ng-show="success">
|
||||
<div class="box-icon success">
|
||||
<i class="fi-check size-24"></i>
|
||||
</div>
|
||||
<span class="text-success size-14">
|
||||
{{success|translate}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="!_merchantData">
|
||||
<div class="row collapse">
|
||||
|
||||
<label for="address" class="left">
|
||||
<span translate>To</span>
|
||||
<i class="fi-info size-12" href="#"
|
||||
data-options="disable_for_touch:true"
|
||||
tooltip-popup-delay='500'
|
||||
tooltip="{{'Enter a valid Bitcoin address. Payment Protocol URLs are also supported'|translate}}"
|
||||
tooltip-trigger="mouseenter"
|
||||
tooltip-placement="right"></i>
|
||||
<small translate ng-hide="!sendForm.address.$pristine && address">required</small>
|
||||
<span translate>To (*)</span>
|
||||
</label>
|
||||
<span translate class="has-error right size-12" ng-show="sendForm.address.$invalid && address">
|
||||
<span class="icon-input"><i class="fi-x"></i></span>
|
||||
Not valid
|
||||
|
||||
<span ng-hide="sendForm.address.$pristine">
|
||||
<span translate class="has-error right size-12" ng-show="sendForm.address.$invalid">
|
||||
<span class="icon-input">
|
||||
<i class="fi-x"></i>
|
||||
</span>
|
||||
Not valid
|
||||
</span>
|
||||
<small class="icon-input right" ng-show="!sendForm.address.$invalid">
|
||||
<i class="fi-check"></i>
|
||||
</small>
|
||||
</span>
|
||||
<small class="icon-input right" ng-show="!sendForm.address.$invalid && address"><i class="fi-check"></i></small>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<input type="text" id="address" name="address" ng-disabled="loading || !!$root.merchant || isPayUri"
|
||||
placeholder="{{'Bitcoin address'|translate}}" ng-model="address" valid-address required>
|
||||
<input type="text" id="address" name="address" ng-disabled="loading || lockAddress" placeholder="{{'Bitcoin address'|translate}}" ng-model="_address" valid-address required>
|
||||
<i class="fi-address-book"></i>
|
||||
<div ng-hide="showScanner || disableScanner">
|
||||
<a class="postfix button black" ng-click="openScanner()"><i class="fi-camera size-24"></i></a>
|
||||
|
@ -58,151 +57,116 @@
|
|||
<a translate class="postfix button warning" ng-click="cancelScanner()"><i class="fi-x size-18"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="scanner"
|
||||
class="row"
|
||||
ng-if="showScanner"
|
||||
ng-include="'views/includes/scanner.html'">
|
||||
<div id="scanner" class="row" ng-if="showScanner" ng-include="'views/includes/scanner.html'">
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="_merchantData">
|
||||
<div class="row collapse" ng-click="openPPModal(_merchantData)">
|
||||
|
||||
<label for="domain">
|
||||
<span translate>Payment to</span>
|
||||
</label>
|
||||
|
||||
<div class="row" ng-init="showAlternative = false">
|
||||
<div class="large-12 medium-12 columns">
|
||||
<div class="m5b right">
|
||||
<span translate class="has-error right size-12" ng-show="sendForm.amount.$invalid &&
|
||||
!sendForm.amount.$pristine && (notValidAmount || amount)">
|
||||
<span class="icon-input"><i class="fi-x"></i></span>
|
||||
Not valid
|
||||
</span>
|
||||
<small class="icon-input right" ng-show="!sendForm.amount.$invalid &&
|
||||
!sendForm.amount.$pristine"><i class="fi-check"></i></small>
|
||||
</div>
|
||||
<div ng-show="!showAlternative">
|
||||
<div class="row collapse">
|
||||
<div class="input">
|
||||
<input type="text" id="domain" name="domain" ng-model="_domain" ng-disabled="1">
|
||||
<i class="fi-lock color-greeni"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="amount"><span translate>Amount in</span> {{$root.wallet.settings.unitName}}
|
||||
<small translate ng-hide="!sendForm.amount.$pristine && amount">required</small>
|
||||
</label>
|
||||
<div class="row" ng-init="showAlternative = false">
|
||||
<div class="large-12 medium-12 columns">
|
||||
<div class="m5b right" ng-hide="sendForm.amount.$pristine">
|
||||
<span translate class="has-error right size-12" ng-show="sendForm.amount.$invalid">
|
||||
<span class="icon-input"><i class="fi-x"></i></span>
|
||||
Not valid
|
||||
</span>
|
||||
<small class="icon-input right" ng-show="!sendForm.amount.$invalid">
|
||||
<i class="fi-check"></i>
|
||||
</small>
|
||||
</div>
|
||||
<div ng-show="!showAlternative">
|
||||
<div class="row collapse">
|
||||
|
||||
<div class="small-9 columns">
|
||||
<div class="input">
|
||||
<input type="number" id="amount"
|
||||
ng-disabled="loading || ($root.merchant && +$root.merchant.total > 0) || isPayUri"
|
||||
name="amount" placeholder="{{'Amount'|translate}}" ng-model="amount"
|
||||
ng-minlength="0.00000001" ng-maxlength="10000000000" valid-amount required
|
||||
autocomplete="off">
|
||||
<i class="icon-bitcoin"></i>
|
||||
</div>
|
||||
<a class="small input-note" title="{{'Send all funds'|translate}}"
|
||||
ng-show="topAmount && (!$root.merchant || +$root.merchant.total === 0)"
|
||||
ng-click="setTopAmount(sendForm)">
|
||||
<span translate>Use all funds</span> {{$root.wallet.settings.unitName}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="small-3 columns pointer" ng-click="showAlternative = true">
|
||||
<span class="postfix">{{$root.wallet.settings.unitName}}</span>
|
||||
<label for="amount">
|
||||
<span translate>Amount (*)</span>
|
||||
</label>
|
||||
|
||||
<div class="small-9 columns">
|
||||
<div class="input">
|
||||
<input type="number" id="amount" ng-disabled="loading || lockAmount" name="amount" placeholder="{{'Amount'|translate}}" ng-minlength="0.00000001" ng-maxlength="10000000000" ng-model="_amount" valid-amount required autocomplete="off">
|
||||
<i class="icon-bitcoin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="showAlternative">
|
||||
<div class="row collapse">
|
||||
<label for="alternative"><span translate>Amount in</span> {{ alternativeName }}
|
||||
<small translate ng-hide="!sendForm.amount.$pristine && amount">required</small>
|
||||
</label>
|
||||
<div class="small-9 columns">
|
||||
<div class="input">
|
||||
<input type="number" id="alternative"
|
||||
ng-disabled="loading || !isRateAvailable || ($root.merchant && +$root.merchant.total > 0) ||
|
||||
isPayUri"
|
||||
name="alternative" placeholder="{{'Amount'|translate}}" ng-model="alternative" requiredautocomplete="off">
|
||||
<i class="icon-usd"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="small-3 columns pointer" ng-click="showAlternative = false">
|
||||
<span class="postfix">{{alternativeIsoCode}}</span>
|
||||
</div>
|
||||
<div class="small-3 columns pointer" ng-click="showAlternative = true">
|
||||
<span class="postfix">{{$root.wallet.settings.unitName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 columns" ng-show="fetchingURL">
|
||||
<h3>
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
Fetching payment
|
||||
</h3>
|
||||
<p> From {{fetchingURL}}
|
||||
</div>
|
||||
|
||||
<div class="large-12 columns" ng-show="!!$root.merchant || isPayUri">
|
||||
<h3 ng-show="!isPayUri">This is a payment protocol transaction</h3>
|
||||
<div class="send-note">
|
||||
<p>
|
||||
<span ng-show="isPayUri">Payment to: </span>
|
||||
<b>{{$root.merchant.pr.pd.memo || address}}</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i>{{amount}} {{$root.wallet.settings.unitName}}</i>
|
||||
<span class="text-gray" ng-if="isRateAvailable">
|
||||
{{ alternative }} {{ alternativeIsoCode }}
|
||||
</span>
|
||||
<span class="text-gray" >
|
||||
(<span translate>Including fee of</span>
|
||||
{{defaultFee}}
|
||||
{{$root.wallet.settings.unitName}})
|
||||
</span>
|
||||
<p ng-show="!!$root.merchant">
|
||||
Expires {{$root.merchant.expiration | amTimeAgo }}
|
||||
[{{$root.merchant.domain}}]
|
||||
<span ng-show="!!$root.merchant.pr.ca"><i class="fi-lock"></i> {{$root.merchant.pr.ca}}</span>
|
||||
<span ng-show="!$root.merchant.pr.ca" style="color:red;weight:bold;"><i class="fi-unlock"></i> Untrusted</span>
|
||||
</p>
|
||||
<div ng-show="showAlternative">
|
||||
<div class="row collapse">
|
||||
<label for="alternative"><span translate>Amount in</span> {{ alternativeName }} (*)
|
||||
</label>
|
||||
<div class="small-9 columns">
|
||||
<div class="input">
|
||||
<input type="number" id="alternative" ng-disabled="loading || !isRateAvailable || lockAmount" name="alternative" placeholder="{{'Amount'|translate}}" ng-model="_alternative" requiredautocomplete="off">
|
||||
<i class="icon-usd"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="small-3 columns pointer" ng-click="showAlternative = false">
|
||||
<span class="postfix">{{alternativeIsoCode}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<label for="comment"><span translate>Note</span>
|
||||
<small translate ng-hide="!sendForm.comment.$pristine">optional</small>
|
||||
<small translate class="has-error" ng-show="sendForm.comment.$invalid && !sendForm.comment.$pristine">too long!</small>
|
||||
</label>
|
||||
<div class="input">
|
||||
<textarea id="comment" ng-disabled="loading"
|
||||
name="comment" placeholder="{{($root.wallet.isShared() ? 'Leave a private message to your copayers' : 'Add a private comment to identify the transaction')}}" ng-model="commentText" ng-maxlength="100"></textarea>
|
||||
<i class="icon-compose"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-6 medium-6 small-6 columns text-left">
|
||||
<a class="button tiny secondary m0" title="Address book" ng-hide="!!$root.merchant || isPayUri" ng-click="openAddressBook()">
|
||||
<i class="fi-address-book"></i> Address book
|
||||
</a>
|
||||
<a ng-click="cancelSend(sendForm)" class="button warning m0" ng-show="!!$root.merchant || isPayUri">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns text-right">
|
||||
<button type="submit" class="button primary m0" ng-disabled="sendForm.$invalid || loading">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner" ng-show="loading"></i>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div><!-- end of row -->
|
||||
|
||||
<div class="row m20b" ng-show="$root.wallet.balanceInfo.alternativeConversionRate > 0">
|
||||
<div class="large-12 columns size-12">
|
||||
<i class="fi-bitcoin-circle"></i>
|
||||
1 BTC = {{$root.wallet.balanceInfo.alternativeConversionRate}} {{alternativeIsoCode}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-show="fetchingURL">
|
||||
<div class="large-12 columns">
|
||||
<p>>>
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
Fetching payment request
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<label for="comment"><span translate>Note</span>
|
||||
<small translate ng-hide="!sendForm.comment.$pristine">optional</small>
|
||||
<small translate class="has-error" ng-show="sendForm.comment.$invalid && !sendForm.comment.$pristine">too long!</small>
|
||||
</label>
|
||||
<div class="input">
|
||||
<textarea id="comment" ng-disabled="loading" name="comment" placeholder="{{($root.wallet.isShared() ? 'Leave a private message to your copayers' : 'Add a private comment to identify the transaction')}}" ng-maxlength="100" ng-model="_comment"></textarea>
|
||||
<i class="icon-compose"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-6 medium-6 small-6 columns text-left">
|
||||
<a class="button tiny secondary m0" title="Address book" ng-hide="_merchantData || lockAddress" ng-click="openAddressBook()">
|
||||
<i class="fi-address-book"></i> Address book
|
||||
</a>
|
||||
<a ng-click="resetForm()" class="button warning m0" ng-show="_merchantData || lockAddress" ng-disabled="loading">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns text-right">
|
||||
<button type="submit" class="button primary m0" ng-disabled="sendForm.$invalid || loading">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner" ng-show="loading"></i> Send
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of row -->
|
||||
|
||||
<div class="row m20b" ng-show="$root.wallet.balanceInfo.alternativeConversionRate > 0">
|
||||
<div class="large-12 columns size-12">
|
||||
<i class="fi-bitcoin-circle"></i> 1 BTC = {{$root.wallet.balanceInfo.alternativeConversionRate}} {{alternativeIsoCode}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<div data-ng-init="" data-ng-controller="UriPaymentController">
|
||||
|
||||
<div class="loading-screen" data-alert>
|
||||
<div class="spinner">
|
||||
<div class="contener_general">
|
||||
<div class="contener_mixte"><div class="ballcolor ball_1"> </div></div>
|
||||
<div class="contener_mixte"><div class="ballcolor ball_2"> </div></div>
|
||||
<div class="contener_mixte"><div class="ballcolor ball_3"> </div></div>
|
||||
<div class="contener_mixte"><div class="ballcolor ball_4"> </div></div>
|
||||
</div>
|
||||
<span class="text-gray size-12" translate>Preparing payment...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue