mirror of https://github.com/BTCPrivate/copay.git
Merge pull request #1981 from cmgustavo/feature/modal-addressbook
Address book is opened in a modal window
This commit is contained in:
commit
2e3e3a55ae
|
@ -1492,6 +1492,32 @@ a.text-warning:hover {color: #FD7262;}
|
||||||
width: 50%;
|
width: 50%;
|
||||||
margin-left: -25%;
|
margin-left: -25%;
|
||||||
}
|
}
|
||||||
|
dialog.large, .reveal-modal.large {
|
||||||
|
max-height: 70%;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: -40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 40em) {
|
||||||
|
dialog.large, .reveal-modal.large {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 1.25rem 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.large span.address-size, .reveal-modal.large span.address-size {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.large table, .reveal-modal.large table {
|
||||||
|
margin: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
-moz-box-shadow: none;
|
||||||
|
-o-box-shadow: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 380px) {
|
@media (max-height: 380px) {
|
||||||
|
@ -1642,6 +1668,15 @@ a.text-warning:hover {color: #FD7262;}
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.addressbook-entry td {
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addressbook-disabled td, .addressbook-disabled td a {
|
||||||
|
color: #8597A7;
|
||||||
|
}
|
||||||
|
|
||||||
/*/////////////////////////////////////////////////*/
|
/*/////////////////////////////////////////////////*/
|
||||||
|
|
||||||
.session-expired {
|
.session-expired {
|
||||||
|
|
|
@ -3,7 +3,7 @@ var bitcore = require('bitcore');
|
||||||
var preconditions = require('preconditions').singleton();
|
var preconditions = require('preconditions').singleton();
|
||||||
|
|
||||||
angular.module('copayApp.controllers').controller('SendController',
|
angular.module('copayApp.controllers').controller('SendController',
|
||||||
function($scope, $rootScope, $window, $timeout, $modal, $filter, isMobile, notification, rateService) {
|
function($scope, $rootScope, $window, $timeout, $modal, $filter, $location, isMobile, notification, rateService) {
|
||||||
var w = $rootScope.wallet;
|
var w = $rootScope.wallet;
|
||||||
preconditions.checkState(w);
|
preconditions.checkState(w);
|
||||||
preconditions.checkState(w.settings.unitToSatoshi);
|
preconditions.checkState(w.settings.unitToSatoshi);
|
||||||
|
@ -99,10 +99,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
||||||
// Empty
|
// Empty
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.showAddressBook = function() {
|
|
||||||
return w && _.keys(w.addressBook).length > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
||||||
|
|
||||||
|
@ -308,62 +304,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.toggleAddressBookEntry = function(key) {
|
|
||||||
w.toggleAddressBookEntry(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.copyAddress = function(address) {
|
|
||||||
$scope.address = address;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.openAddressBookModal = function() {
|
|
||||||
var modalInstance = $modal.open({
|
|
||||||
templateUrl: 'views/modals/address-book.html',
|
|
||||||
windowClass: 'tiny',
|
|
||||||
controller: function($scope, $modalInstance) {
|
|
||||||
|
|
||||||
$scope.submitAddressBook = function(form) {
|
|
||||||
if (form.$invalid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var entry = {
|
|
||||||
"address": form.newaddress.$modelValue,
|
|
||||||
"label": form.newlabel.$modelValue
|
|
||||||
};
|
|
||||||
form.newaddress.$pristine = form.newlabel.$pristine = true;
|
|
||||||
$modalInstance.close(entry);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.cancel = function() {
|
|
||||||
$modalInstance.dismiss('cancel');
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
modalInstance.result.then(function(entry) {
|
|
||||||
|
|
||||||
$timeout(function() {
|
|
||||||
$scope.loading = false;
|
|
||||||
var errorMsg;
|
|
||||||
try {
|
|
||||||
w.setAddressBook(entry.address, entry.label);
|
|
||||||
} catch (e) {
|
|
||||||
errorMsg = e.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO change this notifications
|
|
||||||
if (errorMsg) {
|
|
||||||
notification.error('Error', errorMsg);
|
|
||||||
} else {
|
|
||||||
notification.success('Success', 'New entry has been created');
|
|
||||||
}
|
|
||||||
$rootScope.$digest();
|
|
||||||
}, 500);
|
|
||||||
// reset fields
|
|
||||||
$scope.newaddress = $scope.newlabel = null;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.setTopAmount = function() {
|
$scope.setTopAmount = function() {
|
||||||
$scope.amount = $rootScope.topAmount;
|
$scope.amount = $rootScope.topAmount;
|
||||||
};
|
};
|
||||||
|
@ -599,4 +539,79 @@ angular.module('copayApp.controllers').controller('SendController',
|
||||||
_onChanged(pp);
|
_onChanged(pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.openAddressBook = function() {
|
||||||
|
var modalInstance = $modal.open({
|
||||||
|
templateUrl: 'views/modals/address-book.html',
|
||||||
|
windowClass: 'large',
|
||||||
|
controller: function($scope, $modalInstance) {
|
||||||
|
|
||||||
|
$scope.showForm = null;
|
||||||
|
$scope.addressBook = w.addressBook;
|
||||||
|
|
||||||
|
$scope.hasEntry = function() {
|
||||||
|
return _.keys($scope.addressBook).length > 0 ? true : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toggleAddressBookEntry = function(key) {
|
||||||
|
w.toggleAddressBookEntry(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.copyToSend = function(addr) {
|
||||||
|
$modalInstance.close(addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
$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);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.close = function() {
|
||||||
|
$modalInstance.dismiss('cancel');
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
modalInstance.result.then(function(addr) {
|
||||||
|
$scope.address = addr;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -222,10 +222,6 @@ describe("Unit: Controllers", function() {
|
||||||
expect(scope.title).equal('Create Transaction Proposal');
|
expect(scope.title).equal('Create Transaction Proposal');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if wallet has addressBook', function() {
|
|
||||||
expect(scope.showAddressBook()).equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should validate address with network', function() {
|
it('should validate address with network', function() {
|
||||||
form.newaddress.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
form.newaddress.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
||||||
expect(form.newaddress.$invalid).to.equal(false);
|
expect(form.newaddress.$invalid).to.equal(false);
|
||||||
|
|
|
@ -1,33 +1,90 @@
|
||||||
<h2 translate>Address Book</h2>
|
<div>
|
||||||
<form class="m0" name="addressBookForm" ng-submit="submitAddressBook(addressBookForm)" novalidate>
|
<h1 ng-show="!showForm">Address Book
|
||||||
<div class="row collapse">
|
<small><a class="text-success" href ng-click="toggleForm()"><i class="fi-plus"></i> Add entry</a></small>
|
||||||
<label for="newaddress" class="left"><span translate>Address</span>
|
</h1>
|
||||||
<small translate ng-hide="!addressBookForm.newaddress.$pristine || newaddress">Required</small>
|
<h1 ng-show="showForm">Add a new entry</h1>
|
||||||
</label>
|
<p translate class="text-gray m15b" ng-show="!showForm && !hasEntry()">Empty. Create an alias for your addresses</p>
|
||||||
<span translate class="has-error right size-12" ng-show="addressBookForm.newaddress.$invalid && newaddress">
|
<div class="box-notification" ng-show="success">
|
||||||
<span class="icon-input"><i class="fi-x"></i></span>
|
<div class="box-icon success">
|
||||||
Not valid
|
<i class="size-24 fi-check"></i>
|
||||||
</span>
|
|
||||||
<small class="icon-input right" ng-show="!addressBookForm.newaddress.$invalid && newaddress"><i class="fi-check"></i></small>
|
|
||||||
</div>
|
|
||||||
<div class="input">
|
|
||||||
<input type="text" id="newaddress" name="newaddress" ng-disabled="loading"
|
|
||||||
placeholder="{{'Address'|translate}}" ng-model="newaddress" valid-address required>
|
|
||||||
<i class="fi-address-book"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="newlabel"><span translate>Label</span>
|
|
||||||
<small translate ng-hide="!addressBookForm.newlabel.$pristine || newlabel">Required</small>
|
|
||||||
<div class="input">
|
|
||||||
<input type="text" id="newlabel" name="newlabel" ng-disabled="loading"
|
|
||||||
placeholder="{{'Label'|translate}}" ng-model="newlabel" required>
|
|
||||||
<i class="icon-pricetag"></i>
|
|
||||||
</div>
|
</div>
|
||||||
</label>
|
<span class="size-14 text-success">
|
||||||
<a translate class="m0 button warning small default" ng-click="cancel()">Cancel</a>
|
{{success}}
|
||||||
<input type="submit" class="m0 button small primary right"
|
</span>
|
||||||
ng-disabled="addressBookForm.$invalid || loading"
|
</div>
|
||||||
value="{{'Add'|translate}}">
|
<table class="addressbook" ng-show="!showForm && hasEntry()">
|
||||||
</form>
|
<thead class="show-for-large-up">
|
||||||
<a class="close-reveal-modal" ng-click="cancel()">×</a>
|
<tr>
|
||||||
|
<th translate>Entry</th>
|
||||||
|
<th ng-class="{'hide-for-small-only' : $root.wallet.isShared()}" ng-show="$root.wallet.isShared()" translate>Creator</th>
|
||||||
|
<th class="show-for-large-up" translate>Date</th>
|
||||||
|
<th class="show-for-large-up">Visible</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
class="addressbook-entry"
|
||||||
|
ng-repeat="(addr, info) in addressBook"
|
||||||
|
ng-class="{'addressbook-disabled': info.hidden}">
|
||||||
|
<td ng-click="copyToSend(addr)">
|
||||||
|
<dl>
|
||||||
|
<dt><b>{{info.label}}</b></dt>
|
||||||
|
<dd><span class="address-size">{{::addr}}</span></dd>
|
||||||
|
</dl>
|
||||||
|
</td>
|
||||||
|
<td ng-click="copyToSend(addr)" ng-show="$root.wallet.isShared()" ng-class="{'hide-for-small-only' : $root.wallet.isShared()}">{{$root.wallet.publicKeyRing.nicknameForCopayer(info.copayerId)}}</td>
|
||||||
|
<td ng-click="copyToSend(addr)" class="show-for-large-up"><time>{{::info.createdTs | amCalendar}}</time></td>
|
||||||
|
<td class="show-for-large-up text-center">
|
||||||
|
<a ng-click="toggleAddressBookEntry(addr)" title="{{ info.hidden ? 'Enable' : 'Disable'}} address">
|
||||||
|
<i class="fi-checkbox size-21"
|
||||||
|
ng-class="{'text-success':!info.hidden, 'text-gray':info.hidden}"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="row" ng-show="showForm">
|
||||||
|
<div class="large-6 medium-6 columns large-centered medium-centered">
|
||||||
|
<form class="m0" name="addressBookForm" ng-submit="submitAddressBook(addressBookForm)" novalidate>
|
||||||
|
<div class="box-notification" ng-show="error">
|
||||||
|
<div class="box-icon error">
|
||||||
|
<i class="size-24 fi-x"></i>
|
||||||
|
</div>
|
||||||
|
<span class="size-14 text-warning">
|
||||||
|
{{error}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="row collapse">
|
||||||
|
<label for="newaddress" class="left"><span translate>Address</span>
|
||||||
|
<small translate ng-hide="!addressBookForm.newaddress.$pristine || newaddress">Required</small>
|
||||||
|
</label>
|
||||||
|
<span translate class="has-error right size-12" ng-show="addressBookForm.newaddress.$invalid && newaddress">
|
||||||
|
<span class="icon-input"><i class="fi-x"></i></span>
|
||||||
|
Not valid
|
||||||
|
</span>
|
||||||
|
<small class="icon-input right" ng-show="!addressBookForm.newaddress.$invalid && newaddress"><i class="fi-check"></i></small>
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" name="newaddress"
|
||||||
|
placeholder="{{'Address'|translate}}" ng-model="newaddress" valid-address required>
|
||||||
|
<i class="fi-address-book"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="newlabel"><span translate>Label</span>
|
||||||
|
<small translate ng-hide="!addressBookForm.newlabel.$pristine || newlabel">Required</small>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" name="newlabel"
|
||||||
|
placeholder="{{'Label'|translate}}" ng-model="newlabel" required>
|
||||||
|
<i class="icon-pricetag"></i>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<a translate class="m0 button secondary small default" ng-click="cancel()">Back</a>
|
||||||
|
<input type="submit" class="m0 button small primary right"
|
||||||
|
ng-disabled="addressBookForm.$invalid || loading"
|
||||||
|
value="{{'Add'|translate}}">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="close-reveal-modal" ng-click="close()">×</a>
|
||||||
|
</div>
|
||||||
|
|
|
@ -165,6 +165,9 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="large-6 medium-6 small-6 columns text-left">
|
<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">
|
<a ng-click="cancelSend(sendForm)" class="button warning m0" ng-show="!!$root.merchant || isPayUri">
|
||||||
Cancel
|
Cancel
|
||||||
</a>
|
</a>
|
||||||
|
@ -186,42 +189,5 @@
|
||||||
1 BTC = {{$root.wallet.balanceInfo.alternativeConversionRate}} {{alternativeIsoCode}}
|
1 BTC = {{$root.wallet.balanceInfo.alternativeConversionRate}} {{alternativeIsoCode}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="line-dashed-h m20b"></div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="large-12 columns">
|
|
||||||
<h2 translate>Address Book</h2>
|
|
||||||
<p translate class="text-gray m15b" ng-hide="showAddressBook()">Empty. Create an alias for your addresses</p>
|
|
||||||
<table ng-show="showAddressBook()">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th translate>Label</th>
|
|
||||||
<th translate>Address</th>
|
|
||||||
<th ng-class="{'hide-for-small-only' : $root.wallet.isShared()}" ng-show="$root.wallet.isShared()" translate>Creator</th>
|
|
||||||
<th class="hide-for-small-only" translate>Date</th>
|
|
||||||
<th class="hide-for-small-only">Enable</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
ng-repeat="(addr, info) in $root.wallet.addressBook"
|
|
||||||
ng-class="{'addressbook-disabled': info.hidden}">
|
|
||||||
<td><a ng-click="copyAddress(addr)" title="Copy address">{{info.label}}</a></td>
|
|
||||||
<td class="size-12">{{::addr}}</td>
|
|
||||||
<td ng-show="$root.wallet.isShared()" ng-class="{'hide-for-small-only' : $root.wallet.isShared()}">{{$root.wallet.publicKeyRing.nicknameForCopayer(info.copayerId)}}</td>
|
|
||||||
<td class="hide-for-small-only"><time>{{::info.createdTs | amCalendar}}</time></td>
|
|
||||||
<td class="hide-for-small-only">
|
|
||||||
<a ng-click="toggleAddressBookEntry(addr)" title="{{ info.hidden ? 'Enable' : 'Disable'}} address">
|
|
||||||
<i class="fi-checkbox"
|
|
||||||
ng-class="{'text-success':!info.hidden, 'text-gray':info.hidden}"></i>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<button translate class="button tiny primary" ng-click="openAddressBookModal()">
|
|
||||||
<i class="fi-plus m5r"></i> Add</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue