Skip to content

Commit

Permalink
feat(assets): add an asset transfer dialog
Browse files Browse the repository at this point in the history
Implemented UI and it's validation for assets transfer feature.
  • Loading branch information
beregovoy68 committed Nov 15, 2016
1 parent e5b2ad0 commit 8234110
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 10 deletions.
2 changes: 1 addition & 1 deletion bower.json
Expand Up @@ -24,7 +24,7 @@
"angular-messages": "^1.5.8",
"angular-validation-match": "^1.9.0",
"angular-material": "^1.1.1",
"waves-angular-validate": "git@github.com:beregovoy68/angular-validate.git#^1.1.2",
"waves-angular-validate": "git@github.com:beregovoy68/angular-validate.git#master",
"tooltipster": "^3.3.0"
},
"analytics": false
Expand Down
10 changes: 9 additions & 1 deletion src/index.html
Expand Up @@ -469,7 +469,7 @@ <h1>PORTFOLIO</h1>
</tbody>
</table>
<div ng-controller="assetTransferController as transfer">
<div id="transfer-asset-dialog" waves-dialog ok-button-caption="TRANSFER" ok-button-enabled="!transfer.confirm.pendingTransfer" on-dialog-ok="transfer.submitPayment()">
<div id="transfer-asset-dialog" waves-dialog ok-button-caption="TRANSFER" on-dialog-ok="transfer.submitTransfer()">
<form id="transfer-asset-form" name="transferAssetForm" novalidate ng-validate="transfer.validationOptions">
<h2>ASSET TRANSFER</h2>
<div class="balanceAmt">
Expand Down Expand Up @@ -516,6 +516,14 @@ <h2>ASSET TRANSFER</h2>
</table>
</form>
</div>
<div id="transfer-asset-confirmation" waves-dialog ok-button-caption="CONFIRM" ok-button-enabled="!transfer.confirm.pendingTransfer" on-dialog-ok="transfer.broadcastTransaction()">
<p>You are sending <span class="confirmation-value">{{transfer.confirm.amount.value}}</span>
<span class="confirmation-value">{{transfer.confirm.amount.currency}}</span> with
<span class="confirmation-value">{{transfer.confirm.fee.value}}</span>
<span class="confirmation-value">{{transfer.confirm.fee.currency}}</span> fee <br/>to the address: <span class="confirmation-value">{{transfer.confirm.recipient}}</span>
</p>
<p>Please <span class="fontBold"> CONFIRM </span>to execute or <span class="fontBold"> CANCEL </span> to discard.</p>
</div>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/js/app.js
Expand Up @@ -56,7 +56,7 @@ function AngularApplicationConfig($validatorProvider) {
$validatorProvider.addMethod('decimal', function(value, element, params) {
var maxdigits = angular.isNumber(params) ? params : Currency.WAV.precision;

var regex = new RegExp('^(?:-?\\d+)?(?:\\.\\d{1,' + maxdigits + '})?$');
var regex = new RegExp('^(?:-?\\d+)?(?:\\.\\d{0,' + maxdigits + '})?$');
return this.optional(element) || regex.test(value);
}, 'Amount is expected with a dot (.) as a decimal separator with no more than {0} fraction digits');
$validatorProvider.addMethod('password', function(value, element) {
Expand Down
161 changes: 157 additions & 4 deletions src/js/portfolio/asset.transfer.controller.js
@@ -1,23 +1,176 @@
(function () {
'use strict';

function WavesAssetTransferController($scope, events, autocomplete, applicationContext) {
function WavesAssetTransferController($scope, $timeout, constants, events, autocomplete, applicationContext,
assetService, apiService, dialogService,
formattingService, notificationService) {
var transaction;
var transfer = this;
var minimumFee = new Money(constants.MINIMUM_TRANSACTION_FEE, Currency.WAV);

transfer.availableBalance = 0;
transfer.confirm = {
amount: {
value: '0',
currency: ''
},
fee: {
value: '0',
currency: ''
},
recipient: '',
pendingTransfer: false
};
transfer.autocomplete = angular.copy(autocomplete);
transfer.validationOptions = {};
transfer.autocomplete = autocomplete;
transfer.validationOptions = {
debug: true,
rules: {
assetRecipient: {
required: true,
address: true
},
assetAmount: {
required: true,
decimal: 0,
min: 1
},
assetFee: {
required: true,
decimal: Currency.WAV.precision,
min: minimumFee.toTokens()
}
},
messages: {
assetRecipient: {
required: 'Recipient account number is required'
},
assetAmount: {
required: 'Amount to send is required'
},
assetFee: {
required: 'Transaction fee is required',
decimal: 'Transaction fee must be with no more than ' +
minimumFee.currency.precision + ' digits after the decimal point (.)',
min: 'Transaction fee is too small. It should be greater or equal to ' +
minimumFee.formatAmount(true)
}
}
};
transfer.submitTransfer = submitTransfer;
transfer.broadcastTransaction = broadcastTransaction;

resetPaymentForm();

$scope.$on(events.ASSET_SELECTED, function (event, assetId) {
var asset = applicationContext.cache.assets[assetId];
transfer.availableBalance = asset.balance.formatAmount();
transfer.asset = asset;

// update validation options and check how it affects form validation
transfer.validationOptions.rules.assetAmount.decimal = asset.currency.precision;
var minimumPayment = Money.fromCoins(1, asset.currency);
transfer.validationOptions.rules.assetAmount.min = minimumPayment.toTokens();
transfer.validationOptions.messages.assetAmount.decimal = 'The amount to send must be a number ' +
'with no more than ' + minimumPayment.currency.precision +
' digits after the decimal point (.)';
transfer.validationOptions.messages.assetAmount.min = 'Payment amount is too small. ' +
'It should be greater or equal to ' + minimumPayment.formatAmount(false);
});

function getTransferForm() {
// here we have a direct markup dependency
// but other ways of getting the form from a child scope are even more ugly
return angular.element('#transfer-asset-form').scope().transferAssetForm;
}

function submitTransfer() {
var transferForm = getTransferForm();
var invalid = transferForm.invalid();
transfer.fee.isValid = angular.isDefined(invalid.assetFee) ?
!invalid.assetFee : true;
if (!transferForm.validate(transfer.validationOptions))
// prevent dialog from closing
return false;

var assetTransfer = {
recipient: transfer.recipient,
amount: Money.fromTokens(transfer.amount, transfer.asset.currency),
fee: Money.fromTokens(transfer.autocomplete.getFeeAmount(), Currency.WAV)
};
var sender = {
publicKey: applicationContext.account.keyPair.public,
privateKey: applicationContext.account.keyPair.private
};
// creating the transaction and waiting for confirmation
transaction = assetService.createAssetTransferTransaction(assetTransfer, sender);

// setting data for the confirmation dialog
transfer.confirm.amount.value = assetTransfer.amount.formatAmount(true);
transfer.confirm.amount.currency = assetTransfer.amount.currency.displayName;
transfer.confirm.fee.value = assetTransfer.fee.formatAmount(true);
transfer.confirm.fee.currency = assetTransfer.fee.currency.displayName;
transfer.confirm.recipient = assetTransfer.recipient;

// open confirmation dialog
// doing it async because this method is called while another dialog is open
$timeout(function () {
dialogService.open('#transfer-asset-confirmation');
}, 1);

resetPaymentForm();

// it's ok to close payment dialog
return true;
}

function broadcastTransaction() {
// checking if transaction was saved
if (angular.isUndefined(transaction))
return;

// prevent method execution when there is a pending transfer request
if (transfer.confirm.paymentPending)
return;

//disable confirm button
transfer.confirm.paymentPending = true;

apiService.assets.transfer(transaction).then(function () {
var amount = Money.fromCoins(transaction.amount, transfer.asset);
var address = transaction.recipient;
var displayMessage = 'Sent ' + amount.formatAmount(true) + ' of ' +
transaction.asset.currency.displayName +
'<br/>Recipient ' + address.substr(0,15) + '...<br/>Date: ' +
formattingService.formatTimestamp(transaction.timestamp);
notificationService.notice(displayMessage);
//enable confirm button
transfer.confirm.paymentPending = false;
transaction = undefined;
}, function (response) {
if (angular.isDefined(response.data))
notificationService.error('Error:' + response.data.error + ' - ' + response.data.message);
else
notificationService.error('Request failed. Status: ' + response.status + ' - ' +
response.statusText);
//enable confirm button
transfer.confirm.paymentPending = false;
transaction = undefined;
});
}

function resetPaymentForm() {
transfer.recipient = '';
transfer.amount = '0';
transfer.fee = {
amount: '0.001',
isValid: true
};
}
}

WavesAssetTransferController.$inject = ['$scope', 'portfolio.events', 'autocomplete.fees', 'applicationContext'];
WavesAssetTransferController.$inject = ['$scope', '$timeout', 'constants.ui', 'portfolio.events',
'autocomplete.fees', 'applicationContext', 'assetService', 'apiService', 'dialogService',
'formattingService', 'notificationService'];

angular
.module('app.portfolio')
Expand Down
7 changes: 4 additions & 3 deletions src/js/wallet/wallet.controller.js
Expand Up @@ -51,7 +51,7 @@
recipient: '',
paymentPending: false
};
wallet.transfer = angular.copy(autocomplete);
wallet.transfer = autocomplete;
wallet.paymentValidationOptions = {
rules: {
wavesrecipient: {
Expand Down Expand Up @@ -134,8 +134,9 @@

function submitPayment() {
var paymentForm = getPaymentForm();
wallet.transfer.fee.isValid = angular.isDefined(paymentForm.invalid.wavessendfee) ?
paymentForm.invalid.wavessendfee : true;
var invalid = paymentForm.invalid();
wallet.transfer.fee.isValid = angular.isDefined(invalid.wavessendfee) ?
!invalid.wavessendfee : true;
if (!paymentForm.validate())
// prevent payment dialog from closing if it's not valid
return false;
Expand Down

0 comments on commit 8234110

Please sign in to comment.