New send flow for bitpay card. Fix paypro txStatus. Minor bug fixes

This commit is contained in:
Gustavo Maximiliano Cortez 2016-09-28 17:51:45 -03:00
parent 11a7e96c08
commit 1ac78c21a5
No known key found for this signature in database
GPG Key ID: 15EDAD8D9F2EB1AF
13 changed files with 182 additions and 90 deletions

View File

@ -12,10 +12,15 @@
<div> <div>
<div class="item item-no-bottom-border" translate>Recipient</div> <div class="item item-no-bottom-border" translate>Recipient</div>
<div class="item item-text-wrap item-icon-left bitcoin-address"> <div class="item item-text-wrap item-icon-left item-big-icon-left bitcoin-address">
<i ng-if="isWallet" class="icon ion-briefcase size-21"></i> <i ng-if="isWallet" class="icon ion-briefcase size-21"></i>
<gravatar ng-if="!isWallet" class="send-gravatar" name="{{toName}}" width="30" email="{{toEmail}}"></gravatar> <span ng-if="!isWallet">
<span>{{toName || toAddress}}</span> <gravatar ng-if="!isCard" class="send-gravatar" name="{{toName}}" width="30" email="{{toEmail}}"></gravatar>
<i ng-if="isCard" class="icon big-icon-svg">
<div class="bg icon-bitpay-card"></div>
</i>
</span>
<span ng-class="{'m10l':isCard}">{{toName || toAddress}}</span>
</div> </div>
</div> </div>

View File

@ -101,7 +101,7 @@
</div> </div>
</div> </div>
<div class="camera-icon" ng-show="bitpayCard.bitpayCardCurrentBalance"> <div class="camera-icon" ng-show="bitpayCard.bitpayCardCurrentBalance">
<a ng-click="addFunds = true"> <a ui-sref="tabs.bitpayCard.amount({'isCard': true, 'toName': 'BitPay Card'})">
<i class="icon ion-plus size-21"></i> <i class="icon ion-plus size-21"></i>
</a> </a>
</div> </div>

View File

@ -26,14 +26,21 @@
<div class="item item-icon-left"> <div class="item item-icon-left">
<i ng-if="isWallet" class="icon ion-briefcase size-21"></i> <i ng-if="isWallet" class="icon ion-briefcase size-21"></i>
<gravatar ng-if="!isWallet" class="send-gravatar" name="{{toName}}" width="30" email="{{toEmail}}"></gravatar> <div ng-if="!isWallet">
<span translate>To</span>: {{toAddress}} <gravatar ng-if="!isCard" class="send-gravatar" name="{{toName}}" width="30" email="{{toEmail}}"></gravatar>
<p ng-show="toName">{{toName}}</p> <i ng-if="isCard" class="icon big-icon-svg">
<div class="bg icon-bitpay-card"></div>
</i>
</div>
<div ng-class="{'m10l':isCard}">
<span translate>To</span>: {{toAddress}}
<p ng-show="toName">{{toName}}</p>
<div ng-show="_paypro" ng-click="openPPModal(_paypro)"> <div ng-show="_paypro" ng-click="openPPModal(_paypro)">
<i ng-show="_paypro.verified && _paypro.caTrusted" class="ion-locked" style="color:green"></i> <i ng-show="_paypro.verified && _paypro.caTrusted" class="ion-locked" style="color:green"></i>
<i ng-show="!_paypro.caTrusted" class="ion-unlocked" style="color:red"></i> <i ng-show="!_paypro.caTrusted" class="ion-unlocked" style="color:red"></i>
{{_paypro.domain}} {{_paypro.domain}}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,60 +1,57 @@
<ion-modal-view ng-controller="payproController"> <ion-modal-view ng-controller="payproController">
<ion-header-bar align-title="center" class="tab-bar" ng-style="{'background-color':color}"> <ion-header-bar align-title="center" class="bar-royal" ng-style="{'background-color': color}">
<div class="left-small"> <button class="button button-clear" ng-click="cancel()">
<a ng-click="cancel()" class="p10"> {{'Close' | translate}}
<span class="text-close" translate>Close</span> </button>
</a> <div class="title" translate>
Payment request
</div> </div>
<h1 class="title ellipsis" translate>Payment request</h1>
</ion-header-bar> </ion-header-bar>
<ion-content ng-style="{'background-color': '#F6F7F9'}"> <ion-content>
<div class="modal-content"> <div class="header-modal text-center size-42">
<div class="header-modal text-center p50t"> {{amountStr}}
<div class="size-42"> </div>
{{amountStr}}
</div>
</div>
<h4 class="title m10l" translate>Details</h4> <div class="list">
<ul class="no-bullet size-14 m10t"> <div class="item item-divider" translate>
<li class="line-b p10 oh"> Details
<span class="text-gray" translate>Pay To</span> </div>
<span class="right enable_text_select">{{_paypro.domain}}</span> <div class="item">
</li> {{'Pay To'|translate}}
<li class="line-b p10 oh" ng-if="_paypro.toAddress"> <span class="item-note">{{_paypro.domain}}</span>
<span class="text-gray" translate>Address</span> </div>
<span class="right enable_text_select">{{_paypro.toAddress}}</span> <div class="item" ng-if="_paypro.toAddress">
</li> {{'Address'|translate}}
<li class="line-b p10 oh"> <span class="item-note">{{_paypro.toAddress}}</span>
<span class="text-gray" translate>Certified by</span> </div>
<span class="right text-right"> <div class="item">
{{'Certified by'|translate}}
<span class="item-note">
<span ng-show="_paypro.caTrusted"> <span ng-show="_paypro.caTrusted">
<i class="fi-lock color-greeni"></i> <i class="ion-locked" style="color:green"></i>
{{_paypro.caName}}<br> {{_paypro.caName}}<br>
<span translate>(Trusted)</span> <span translate>(Trusted)</span>
</span> </span>
<span ng-show="!_paypro.caTrusted"> <span ng-show="!_paypro.caTrusted">
<span ng-show="_paypro.selfSigned"> <span ng-show="_paypro.selfSigned">
<i class="fi-unlock color-yellowi"></i> <span translate>Self-signed Certificate</span> <i class="ion-unlocked" style="color:red"></i> <span translate>Self-signed Certificate</span>
</span> </span>
<span ng-show="!_paypro.selfSigned"> <span ng-show="!_paypro.selfSigned">
<i class="fi-unlock color-yellowi"></i>{{_paypro.caName}}<br> <i class="ion-locked" style="color:yellow"></i>{{_paypro.caName}}<br>
<span translate>WARNING: UNTRUSTED CERTIFICATE</span> <span translate>WARNING: UNTRUSTED CERTIFICATE</span>
</span> </span>
</span> </span>
</span> </span>
</li> </div>
<li class="line-b p10 oh" ng-if="_paypro.memo"> <div class="item" ng-if="_paypro.memo">
<span class="text-gray" translate>Memo</span> {{'Memo'|translate}}
<span class="right">{{_paypro.memo}}</span> <span class="item-note wrapword">{{_paypro.memo}}</span>
</li> </div>
<li class="line-b p10 oh" ng-if="_paypro.expires"> <div class="item" ng-if="_paypro.expires">
<span class="text-gray" translate>Expires</span> {{'Expires'|translate}}
<span class="right">{{_paypro.expires * 1000 | amTimeAgo }}</span> <span class="item-note">{{_paypro.expires * 1000 | amTimeAgo }}</span>
</li> </div>
</ul>
</div> </div>
<div class="extra-margin-bottom"></div>
</ion-content> </ion-content>
</ion-modal-view> </ion-modal-view>

View File

@ -4,13 +4,14 @@
<div ng-show="tx.amountStr" class="m20t size-36"> <div ng-show="tx.amountStr" class="m20t size-36">
{{tx.amountStr}} {{tx.amountStr}}
</div> </div>
<div class="size-16 text-gray m10v"> <div class="size-24 text-gray m20v">
<span translate>Sent</span> <span ng-if="!fromBitPayCard" translate>Sent</span>
<span ng-if="fromBitPayCard" translate>Funds sent</span>
</div> </div>
<div class="text-center m20t" ng-if="entryExist || !fromSendTab"> <div class="text-center m20t" ng-if="entryExist || !fromSendTab || fromPayPro">
<a class="button button-positive" ng-click="cancel()" translate>OKAY</a> <a class="button button-positive" ng-click="cancel()" translate>OKAY</a>
</div> </div>
<div class="collect-address" ng-if="!entryExist && fromSendTab"> <div class="collect-address" ng-if="!entryExist && fromSendTab && !fromPayPro">
<div class="row"> <div class="row">
<p translate class="col">Would you like to add this address to your address book?</p> <p translate class="col">Would you like to add this address to your address book?</p>
</div> </div>
@ -40,7 +41,7 @@
<div ng-if="type == 'created'" class="popup-txsigned text-center m30tp"> <div ng-if="type == 'created'" class="popup-txsigned text-center m30tp">
<i class="icon ion-checkmark-round"></i> <i class="icon ion-checkmark-round"></i>
<div class="text-center size-18 tu text-bold m20t"> <div class="text-center size-24 tu text-bold m20v">
<span translate>Payment Proposal Created</span> <span translate>Payment Proposal Created</span>
</div> </div>
<div class="text-center"> <div class="text-center">
@ -52,7 +53,7 @@
<div ng-if="type == 'accepted'" class="popup-txsigned text-center m30tp"> <div ng-if="type == 'accepted'" class="popup-txsigned text-center m30tp">
<i class="icon ion-checkmark-round"></i> <i class="icon ion-checkmark-round"></i>
<div class="text-center size-18 tu text-bold m20t"> <div class="text-center size-24 tu text-bold m20v">
<span translate>Payment Accepted</span> <span translate>Payment Accepted</span>
</div> </div>
<div class="text-center"> <div class="text-center">
@ -62,7 +63,7 @@
<div ng-if="type=='rejected'" class="popup-txrejected text-center m30tp"> <div ng-if="type=='rejected'" class="popup-txrejected text-center m30tp">
<i class="icon ion-close-round"></i> <i class="icon ion-close-round"></i>
<div class="text-center size-18 tu text-bold m20t"> <div class="text-center size-24 tu text-bold m20v">
<span translate>Payment Rejected</span> <span translate>Payment Rejected</span>
</div> </div>
<div class="text-center"> <div class="text-center">

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('amountController', function($rootScope, $scope, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService) { angular.module('copayApp.controllers').controller('amountController', function($rootScope, $scope, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, bitpayCardService, popupService) {
var unitToSatoshi; var unitToSatoshi;
var satToUnit; var satToUnit;
@ -10,18 +10,20 @@ angular.module('copayApp.controllers').controller('amountController', function($
var SMALL_FONT_SIZE_LIMIT = 13; var SMALL_FONT_SIZE_LIMIT = 13;
var LENGTH_EXPRESSION_LIMIT = 19; var LENGTH_EXPRESSION_LIMIT = 19;
$scope.isWallet = $stateParams.isWallet;
$scope.toAddress = $stateParams.toAddress;
$scope.toName = $stateParams.toName;
$scope.toEmail = $stateParams.toEmail;
$scope.$on('$ionicView.leave', function() { $scope.$on('$ionicView.leave', function() {
angular.element($window).off('keydown'); angular.element($window).off('keydown');
}); });
$scope.$on("$ionicView.enter", function(event, data) { $scope.$on("$ionicView.enter", function(event, data) {
if (!$stateParams.toAddress) { $scope.isWallet = data.stateParams.isWallet;
$scope.isCard = data.stateParams.isCard;
$scope.toAddress = data.stateParams.toAddress;
$scope.toName = data.stateParams.toName;
$scope.toEmail = data.stateParams.toEmail;
$scope.showAlternativeAmount = !!$scope.isCard;
if (!$scope.isCard && !$stateParams.toAddress) {
$log.error('Bad params at amount') $log.error('Bad params at amount')
throw ('bad params'); throw ('bad params');
} }
@ -97,7 +99,6 @@ angular.module('copayApp.controllers').controller('amountController', function($
}; };
$scope.pushOperator = function(operator) { $scope.pushOperator = function(operator) {
console.log('[amount.js.90:operator:]', operator); //TODO
if (!$scope.amount || $scope.amount.length == 0) return; if (!$scope.amount || $scope.amount.length == 0) return;
$scope.amount = _pushOperator($scope.amount); $scope.amount = _pushOperator($scope.amount);
@ -185,14 +186,50 @@ angular.module('copayApp.controllers').controller('amountController', function($
$scope.finish = function() { $scope.finish = function() {
var _amount = evaluate(format($scope.amount)); var _amount = evaluate(format($scope.amount));
var amount = $scope.showAlternativeAmount ? fromFiat(_amount).toFixed(unitDecimals) : _amount.toFixed(unitDecimals);
$state.transitionTo('tabs.send.confirm', { if ($scope.isCard) {
isWallet: $scope.isWallet, var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount));
toAmount: amount * unitToSatoshi,
toAddress: $scope.toAddress, var dataSrc = {
toName: $scope.toName, amount: amountUSD,
toEmail: $scope.toEmail currency: 'USD'
}); };
ongoingProcess.set('Processing Transaction...', true);
$timeout(function() {
bitpayCardService.topUp(dataSrc, function(err, invoiceId) {
if (err) {
ongoingProcess.set('Processing Transaction...', false);
popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err));
return;
}
bitpayCardService.getInvoice(invoiceId, function(err, data) {
ongoingProcess.set('Processing Transaction...', false);
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err));
return;
}
var payProUrl = data.paymentUrls.BIP73;
$state.transitionTo('tabs.bitpayCard.confirm', {
isCard: $scope.isCard,
toName: $scope.toName,
paypro: payProUrl
});
});
});
});
} else {
var amount = $scope.showAlternativeAmount ? fromFiat(_amount).toFixed(unitDecimals) : _amount.toFixed(unitDecimals);
$state.transitionTo('tabs.send.confirm', {
isWallet: $scope.isWallet,
toAmount: amount * unitToSatoshi,
toAddress: $scope.toAddress,
toName: $scope.toName,
toEmail: $scope.toEmail
});
}
}; };
}); });

View File

@ -4,15 +4,15 @@ angular.module('copayApp.controllers').controller('confirmController', function(
var cachedTxp = {}; var cachedTxp = {};
var isChromeApp = platformInfo.isChromeApp; var isChromeApp = platformInfo.isChromeApp;
$scope.isWallet = $stateParams.isWallet;
$scope.toAmount = $stateParams.toAmount;
$scope.toAddress = $stateParams.toAddress;
$scope.toName = $stateParams.toName;
$scope.toEmail = $stateParams.toEmail;
$scope.description = $stateParams.description;
$scope.paypro = $stateParams.paypro;
$scope.$on("$ionicView.enter", function(event, data) { $scope.$on("$ionicView.enter", function(event, data) {
$scope.isWallet = data.stateParams.isWallet;
$scope.isCard = data.stateParams.isCard;
$scope.toAmount = data.stateParams.toAmount;
$scope.toAddress = data.stateParams.toAddress;
$scope.toName = data.stateParams.toName;
$scope.toEmail = data.stateParams.toEmail;
$scope.description = data.stateParams.description;
$scope.paypro = data.stateParams.paypro;
initConfirm(); initConfirm();
}); });
@ -243,7 +243,8 @@ angular.module('copayApp.controllers').controller('confirmController', function(
walletService.createTx(wallet, txp, function(err, ctxp) { walletService.createTx(wallet, txp, function(err, ctxp) {
if (err) { if (err) {
return setSendError(err); setSendError(err);
return cb(err);
} }
return cb(null, ctxp); return cb(null, ctxp);
}); });
@ -312,8 +313,4 @@ angular.module('copayApp.controllers').controller('confirmController', function(
if (err) return setSendError(err); if (err) return setSendError(err);
}); });
}; };
$scope.cancel = function() {
$state.go('tabs.send');
};
}); });

View File

@ -1,9 +1,13 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('txStatusController', function($scope, $timeout, $state, $ionicHistory, $log, addressbookService) { angular.module('copayApp.controllers').controller('txStatusController', function($scope, $timeout, $state, $stateParams, $ionicHistory, $log, addressbookService) {
if ($scope.cb) $timeout($scope.cb, 100); if ($scope.cb) $timeout($scope.cb, 100);
$scope.fromSendTab = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName === "tabs.send.amount" ||  "tabs.send";
var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName;
$scope.fromSendTab = previousView.match(/tabs.send/) ? true : false;
$scope.fromBitPayCard = previousView.match(/tabs.bitpayCard/) ? true : false;
$scope.fromPayPro = $stateParams.paypro ? true : false;
$scope.cancel = function() { $scope.cancel = function() {
$scope.txStatusModal.hide(); $scope.txStatusModal.hide();
@ -13,6 +17,11 @@ angular.module('copayApp.controllers').controller('txStatusController', function
$timeout(function() { $timeout(function() {
$state.transitionTo('tabs.home'); $state.transitionTo('tabs.home');
}, 100); }, 100);
} else if ($scope.fromBitPayCard) {
$ionicHistory.removeBackView();
$timeout(function() {
$state.transitionTo('tabs.bitpayCard');
}, 100);
} }
}; };
@ -24,7 +33,7 @@ angular.module('copayApp.controllers').controller('txStatusController', function
}); });
$ionicHistory.removeBackView(); $ionicHistory.removeBackView();
$state.go('tabs.send.addressbook', { $state.go('tabs.send.addressbook', {
fromSendTab: true, fromSendTab: $scope.fromSendTab,
addressbookEntry: addressbookEntry addressbookEntry: addressbookEntry
}); });
} }

View File

@ -33,6 +33,8 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
'tabs.preferences.backup', 'tabs.preferences.backup',
'tabs.receive.backupWarning', 'tabs.receive.backupWarning',
'tabs.receive.backup', 'tabs.receive.backup',
'tabs.bitpayCard.amount',
'tabs.bitpayCard.confirm',
]; ];
$rootScope.$on('$ionicView.beforeEnter', function() { $rootScope.$on('$ionicView.beforeEnter', function() {

View File

@ -852,6 +852,24 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
} }
} }
}) })
.state('tabs.bitpayCard.amount', {
url: '/amount/:isCard/:toName',
views: {
'tab-home@tabs': {
controller: 'amountController',
templateUrl: 'views/amount.html'
}
}
})
.state('tabs.bitpayCard.confirm', {
url: '/confirm/:isCard/:toAddress/:toName/:toAmount/:toEmail/:description/:paypro',
views: {
'tab-home@tabs': {
controller: 'confirmController',
templateUrl: 'views/confirm.html'
}
}
})
.state('tabs.bitpayCard.preferences', { .state('tabs.bitpayCard.preferences', {
url: '/preferences', url: '/preferences',
views: { views: {

View File

@ -116,3 +116,16 @@ ion-header-bar{
.card{ .card{
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 3px rgba(0, 0, 0, 0.3);
} }
/* Wrap text from item-note */
.item-note{
white-space: -moz-pre-wrap !important;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
white-space: pre-wrap;
word-wrap: break-word;
white-space: -webkit-pre-wrap;
word-break: break-all;
white-space: normal;
}

View File

@ -1,4 +1,7 @@
#view-amount { #view-amount {
.icon-bitpay-card {
background-image: url("../img/icon-bitpay.svg");
}
@media(max-width: 480px) { @media(max-width: 480px) {
.bitcoin-address { .bitcoin-address {
.icon { .icon {

View File

@ -1,4 +1,7 @@
#view-confirm { #view-confirm {
.icon-bitpay-card {
background-image: url("../img/icon-bitpay.svg");
}
.slide-to-pay{ .slide-to-pay{
bottom: 149px; bottom: 149px;
} }