From ad186824faff7fbe35f865d91deaaa8084f6a3ff Mon Sep 17 00:00:00 2001 From: Benoit Lavenier <benoit.lavenier@e-is.pro> Date: Mon, 30 May 2016 09:10:22 +0200 Subject: [PATCH] Add transfer form validation, Fix New Account modal recall, Fix Wallet avatar icon, Add actions on menu, Add rememberMe on Login --- package.json | 2 +- www/i18n/locale-en.json | 14 +++++--- www/i18n/locale-fr-FR.json | 14 +++++--- www/js/config.js | 4 +-- www/js/controllers/app-controllers.js | 20 +++++++---- www/js/controllers/home-controllers.js | 9 +++-- www/js/controllers/transfer-controllers.js | 18 +++++++--- www/js/services/utils-services.js | 2 +- www/js/services/wallet-services.js | 41 ++++++++++++---------- www/templates/home/new_account_wizard.html | 11 ++++-- www/templates/login.html | 19 ++++++++-- www/templates/menu.html | 26 ++++++++++++-- www/templates/wallet/modal_transfer.html | 2 +- www/templates/wallet/new_transfer.html | 4 ++- www/templates/wallet/transfer_form.html | 40 ++++++++++++++++++--- www/templates/wallet/view_wallet.html | 4 +-- 16 files changed, 171 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index fa5eca2a9..7d7062d8a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "0.1.4", + "version": "0.1.5", "description": "A webapp client for Duniter network", "dependencies": { "gulp": "^3.9.1", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 7e683b611..30b71f710 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -5,6 +5,7 @@ "APP_BUILD_DATE": "- build {{buildDate}}", "PUBKEY": "Public key", "BTN_OK": "OK", + "BTN_SEND": "Send", "BTN_SHOW": "Show", "BTN_SHOW_PUBKEY": "Show key", "BTN_RELATIVE_UNIT": "Use relative unit", @@ -36,6 +37,8 @@ "CURRENCY": "Currency", "CURRENCIES": "Currencies", "ACCOUNT": "My Account", + "TRANSFER": "Pay", + "SCAN": "Scan", "SETTINGS": "Settings" }, "HOME": { @@ -159,8 +162,8 @@ "TO": "To", "AMOUNT": "Amount", "AMOUNT_HELP": "Amount", - "COMMENTS": "Reference", - "COMMENTS_HELP": "Reference (optional)", + "COMMENT": "Reference", + "COMMENT_HELP": "Reference (optional)", "BTN_SEND": "Send", "BTN_RELATIVE_UNIT": "Amount in relative unit ?", "MODAL": { @@ -259,7 +262,9 @@ "UNKNOWN_ERROR": "Unknown error", "CRYPTO_UNKNOWN_ERROR": "Your browser is not compatible with cryptographic features.", "FIELD_REQUIRED": "This field is required.", - "FIELD_TOO_SHORT": "This field is too short.", + "FIELD_TOO_SHORT": "This field value is too short.", + "FIELD_TOO_LONG": "This field value is exeeding max length.", + "FIELD_ACCENT": "Accent character not allowed", "PASSWORD_NOT_CONFIRMED": "Must match previous password.", "SEND_IDENTITY_FAILED": "Error while trying to register.", "SEND_CERTIFICATION_FAILED": "Could not certify identity.", @@ -287,7 +292,8 @@ "AMOUNT_REQUIRED": "Amount is required.", "AMOUNT_NEGATIVE": "Negative amount not allowed.", "NOT_ENOUGH_CREDIT": "Not enough credit.", - "INVALID_NODE_SUMMARY": "Unreachable node or invalid address" + "INVALID_NODE_SUMMARY": "Unreachable node or invalid address", + "INVALID_COMMENT": "Field 'reference' has a bad format." }, "INFO": { "POPUP_TITLE": "Information", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index da6ea34eb..25eb4ebe2 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -5,6 +5,7 @@ "APP_BUILD_DATE": "- build {{buildDate}}", "PUBKEY": "Clé publique", "BTN_OK": "OK", + "BTN_SEND": "Envoyer", "BTN_SHOW": "Voir", "BTN_SHOW_PUBKEY": "Voir la clé", "BTN_RELATIVE_UNIT": "Afficher en unité relative ?", @@ -36,6 +37,8 @@ "CURRENCY": "Monnaie", "CURRENCIES": "Monnaies", "ACCOUNT": "Mon compte", + "TRANSFER": "Payer", + "SCAN": "Scanner", "SETTINGS": "Paramètres" }, "HOME": { @@ -59,7 +62,7 @@ "NODE_HELP": "server.domain.com:port", "USE_LOCAL_STORAGE": "Activer le stockage local", "AUTHENTICATION_SETTINGS": "Authentification", - "REMEMBER_ME": "Se rappeller de moi", + "REMEMBER_ME": "Se souvenir de moi", "POPUP_NODE": { "TITLE" : "Noeud Duniter", "HELP" : "Saisissez l'adresse du noeud que vous voulez utiliser :" @@ -159,8 +162,8 @@ "TO": "A", "AMOUNT": "Montant", "AMOUNT_HELP": "Montant", - "COMMENTS": "Référence", - "COMMENTS_HELP": "Référence (optionnelle)", + "COMMENT": "Référence", + "COMMENT_HELP": "Référence (optionnelle)", "BTN_SEND": "Envoyer", "BTN_RELATIVE_UNIT": "Montant en unité relative ?", "MODAL": { @@ -260,6 +263,8 @@ "CRYPTO_UNKNOWN_ERROR": "Votre navigateur ne semble pas compatible avec les fonctionnalités de cryptographie.", "FIELD_REQUIRED": "Champ obligatoire.", "FIELD_TOO_SHORT": "Valeur trop courte.", + "FIELD_TOO_LONG": "Valeur trop longue", + "FIELD_ACCENT": "Caractères accentués non autorisés", "PASSWORD_NOT_CONFIRMED": "Ne correspond pas au mot de passe.", "SEND_IDENTITY_FAILED": "Erreur pendant l'inscription.", "SEND_CERTIFICATION_FAILED": "Erreur lors de la certification de l'identité.", @@ -287,7 +292,8 @@ "AMOUNT_REQUIRED": "Le montant est obligatoire.", "AMOUNT_NEGATIVE": "Montant négatif non autorisé.", "NOT_ENOUGH_CREDIT": "Crédit insufissant.", - "INVALID_NODE_SUMMARY": "Noeud injoignable ou adresse invalide" + "INVALID_NODE_SUMMARY": "Noeud injoignable ou adresse invalide.", + "INVALID_COMMENT": "Le champ 'référence' ne doit pas contenir de caractères accentués." }, "INFO": { "POPUP_TITLE": "Information", diff --git a/www/js/config.js b/www/js/config.js index 54af8481c..9525d199a 100644 --- a/www/js/config.js +++ b/www/js/config.js @@ -14,8 +14,8 @@ angular.module("cesium.config", []) "TIMEOUT": 4000, "DEBUG": false, "NATIVE_TRANSITION": false, - "VERSION": "0.1.4", - "BUILD_DATE": "2016-05-28T17:53:04.922Z" + "VERSION": "0.1.5", + "BUILD_DATE": "2016-05-30T07:08:26.918Z" }) ; \ No newline at end of file diff --git a/www/js/controllers/app-controllers.js b/www/js/controllers/app-controllers.js index b44c534d4..2b5c0edd1 100644 --- a/www/js/controllers/app-controllers.js +++ b/www/js/controllers/app-controllers.js @@ -31,7 +31,9 @@ angular.module('cesium.app.controllers', ['cesium.services']) function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, $state, $timeout, $ionicSideMenuDelegate, $ionicHistory) { // Login modal $scope.loginModal = null; - $scope.loginData = {}; + $scope.loginData = { + rememberMe: Wallet.defaultSettings.rememberMe + }; $rootScope.viewFirstEnter = false; $scope.$on('$ionicView.enter', function(e, $state) { @@ -66,7 +68,7 @@ function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUti }, 2000); } }; - + // Login and load wallet $scope.loadWallet = function() { return $q(function(resolve, reject){ @@ -117,7 +119,9 @@ function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUti // Triggered in the login modal to close it $scope.cancelLogin = function() { var callback = $scope.loginData.callbacks.cancel; - $scope.loginData = {}; // Reset login data + $scope.loginData = { // Reset login data + rememberMe: Wallet.defaultSettings.rememberMe + }; $scope.loginForm.$setPristine(); // Reset form $scope.loginModal.hide(); if (!!callback) { @@ -136,7 +140,13 @@ function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUti .then(function(){ // Call wallet login, then execute callback function Wallet.login($scope.loginData.username, $scope.loginData.password) - .then(function(){ + .then(function(walletData){ + walletData.settings.rememberMe = $scope.formData.rememberMe; + if (walletData.settings.rememberMe) { + walletData.settings.useLocalStorage = true; + Wallet.store(); + } + var callback = $scope.loginData.callbacks.success; $scope.loginData = {}; // Reset login data $scope.loginForm.$setPristine(); // Reset form @@ -181,11 +191,9 @@ function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUti // Logout $scope.logout = function() { - UIUtils.loading.show(); Wallet.logout() .then(function() { $ionicSideMenuDelegate.toggleLeft(); - UIUtils.loading.hide() $state.go('app.home'); }) .catch(UIUtils.onError()); diff --git a/www/js/controllers/home-controllers.js b/www/js/controllers/home-controllers.js index 6b0666edd..0e5d9963d 100644 --- a/www/js/controllers/home-controllers.js +++ b/www/js/controllers/home-controllers.js @@ -55,8 +55,9 @@ function NewAccountWizardController($scope, $ionicModal, $state, $ionicSideMenuD $timeout(function(){ $scope.accountData = {}; $scope.accountForm = {}; - $scope.slides.slider.destroy(); - delete $scope.slides.slider; + $scope.newAccountModal.remove(); + $scope.newAccountModal = null; + $scope.slides.slider = null; }, 200); }; @@ -118,6 +119,10 @@ function NewAccountWizardController($scope, $ionicModal, $state, $ionicSideMenuD } }; + //Cleanup the modal when we're done with it! + $scope.$on('$destroy', function() { + }); + $scope.selectCurrency = function(currency) { $scope.accountData.currency = currency; $scope.slideNext(); diff --git a/www/js/controllers/transfer-controllers.js b/www/js/controllers/transfer-controllers.js index 5040a13b7..98f666639 100644 --- a/www/js/controllers/transfer-controllers.js +++ b/www/js/controllers/transfer-controllers.js @@ -66,16 +66,17 @@ function TransferController($scope, $ionicModal, $state, BMA, Wallet, UIUtils, $ function TransferModalController($scope, $ionicModal, $state, BMA, Wallet, UIUtils, $timeout, System) { $scope.walletData = {}; - $scope.transferForm = {}; $scope.convertedBalance = 0; + //$scope.transferForm = {}; $scope.formData = { destPub: null, amount: null, - comments: null, + comment: null, useRelative: Wallet.defaultSettings.useRelative }; $scope.dest = null; $scope.udAmount = null; + $scope.commentPattern = Wallet.regex.COMMENT; WotLookupController.call(this, $scope, BMA, $state, UIUtils, $timeout, System); @@ -182,6 +183,11 @@ function TransferModalController($scope, $ionicModal, $state, BMA, Wallet, UIUti }; $scope.doTransfer = function() { + $scope.transferForm.$submitted=true; + if(!$scope.transferForm.$valid) { + return; + } + UIUtils.loading.show(); var amount = $scope.formData.amount; @@ -191,7 +197,7 @@ function TransferModalController($scope, $ionicModal, $state, BMA, Wallet, UIUti amount.replace(new RegExp('[.,]'), '.'); } - Wallet.transfer($scope.formData.destPub, amount, $scope.formData.comments) + Wallet.transfer($scope.formData.destPub, amount, $scope.formData.comment) .then(function() { var callback = $scope.formData.callback; $scope.formData = {}; // Reset form data @@ -207,7 +213,11 @@ function TransferModalController($scope, $ionicModal, $state, BMA, Wallet, UIUti $state.go('app.view_wallet'); } }) - .catch(UIUtils.onError('ERROR.SEND_TX_FAILED')); + .catch(// TODO BLA remoive function + function(err) { + UIUtils.onError('ERROR.SEND_TX_FAILED')(err); + } + ); }; $scope.closeLookup = function() { diff --git a/www/js/services/utils-services.js b/www/js/services/utils-services.js index a2570fafd..624d5aea2 100644 --- a/www/js/services/utils-services.js +++ b/www/js/services/utils-services.js @@ -100,7 +100,7 @@ angular.module('cesium.utils.services', ['ngResource']) // Otherwise, log to console and display error else { console.error('>>>>>>>' , err); - hideLoading(); + hideLoading(10); // timeout, to avoid bug on transfer (when error on reference) alertError(fullMsg, subtitle); } }; diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index 5eb79b4c4..46ee24030 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -8,6 +8,10 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' var + USER_ID = "[A-Za-z0-9_-]*", + PUBKEY = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}", + COMMENT = "[ a-zA-Z0-9-_:/;*\\[\\]()?!^\\+=@&~#{}|\\\\<>%.]{0,255}", + defaultSettings = { useRelative: true, timeWarningExpire: 129600 /*TODO: =1.5j est-ce suffisant ?*/, @@ -79,6 +83,10 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' } }, + exact = function(regexpContent) { + return new RegExp("^" + regexpContent + "$"); + }, + reduceTxAndPush = function(txArray, result, processedTxMap) { if (!txArray || txArray.length === 0) { return; @@ -309,7 +317,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' }); }, - loadSources = function(refresh) { + loadSources = function() { return $q(function(resolve, reject) { // Get transactions BMA.tx.sources({pubkey: data.pubkey}) @@ -328,9 +336,9 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' else { src.consumed = false; } - //if (!src.consumed) { + if (!src.consumed) { balance += src.amount; - //} + } sources.push(src); sources[srcKey] = src; }); @@ -448,7 +456,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' }); }, - loadData = function(refresh) { + loadData = function() { if (data.loaded) { return refreshData(); } @@ -468,7 +476,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' loadMembers(), // Get sources - loadSources(false), + loadSources(), // Get requirements loadRequirements(), @@ -499,23 +507,14 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' return $q(function(resolve, reject){ $q.all([ - // Get the UD informations - BMA.blockchain.stats.ud() - .then(function(res){ - if (res.result.blocks.length) { - var lastBlockWithUD = res.result.blocks[res.result.blocks.length - 1]; - return BMA.blockchain.block({ block: lastBlockWithUD }) - .then(function(block){ - data.currentUD = block.dividend; - }); - } - }), + // Get UDs + loadUDs(), // Get requirements loadRequirements(), // Get sources - loadSources(true), + loadSources(), // Get transactions loadTransactions() @@ -532,6 +531,9 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' transfer = function(destPub, amount, comments) { return $q(function(resolve, reject) { + if (!exact(COMMENT).test(comments)){ + reject({message:'ERROR.INVALID_COMMENT'}); return; + } if (!isLogin()){ reject({message:'ERROR.NEED_LOGIN_FIRST'}); return; } @@ -798,7 +800,10 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' // serialization toJson: toJson, fromJson: fromJson, - defaultSettings: defaultSettings + defaultSettings: defaultSettings, + regex: { + COMMENT: exact(COMMENT) + } }; }; diff --git a/www/templates/home/new_account_wizard.html b/www/templates/home/new_account_wizard.html index 2e202e3be..fe6d1e1d4 100644 --- a/www/templates/home/new_account_wizard.html +++ b/www/templates/home/new_account_wizard.html @@ -129,10 +129,15 @@ </div> </div> + <div class="padding hidden-xs text-right"> + <button class="button button-clear button-dark ink" ng-click="cancel()" type="button" translate>COMMON.BTN_CANCEL + </button> + <button class="button button-positive ink" type="submit" translate> + COMMON.BTN_SEND + </button> + </div> + <div class="padding hidden-xs"> - <button class="button button-block button-positive" type="submit"> - {{'COMMON.BTN_OK' | translate}} - </button> </div> </form> </ion-content> diff --git a/www/templates/login.html b/www/templates/login.html index 6bbdffa6c..ec8e011e2 100644 --- a/www/templates/login.html +++ b/www/templates/login.html @@ -1,4 +1,4 @@ -<ion-modal-view class="login modal slide-in-up ng-enter active ng-enter-active"> +<ion-modal-view class="login"> <ion-header-bar class="bar-positive"> <button class="button button-clear visible-xs" ng-click="cancelLogin()" translate>COMMON.BTN_CANCEL </button> @@ -52,8 +52,18 @@ </div> </div> - <!-- remember me - <ion-checkbox ng-model="isChecked">Checkbox Label</ion-checkbox>--> + <!-- remember me --> + <div class="item item-toggle dark hidden-xs"> + <div class="input-label"> + {{'SETTINGS.REMEMBER_ME' | translate}} + </div> + <label class="toggle toggle-royal"> + <input type="checkbox" ng-model="loginData.rememberMe"> + <div class="track"> + <div class="handle"></div> + </div> + </label> + </div> <!-- Show public key --> <div class="item item-icon-left item-button-right left"> @@ -67,6 +77,9 @@ <h3 class="gray text-no-wrap" ng-if="loginData.pubkey"> {{loginData.pubkey}} </h3> + <h3 ng-if="loginData.computing"> + <ion-spinner icon="android"></ion-spinner> + </h3> </div> </div> diff --git a/www/templates/menu.html b/www/templates/menu.html index de6f63baf..1dc0299da 100644 --- a/www/templates/menu.html +++ b/www/templates/menu.html @@ -69,18 +69,38 @@ <i class="icon ion-card"></i> <span translate>MENU.ACCOUNT</span> </ion-item> + <!-- <ion-item menu-close ng-click="addAccount()"> Add account </ion-item> --> <ion-item menu-close class="item item-icon-left" href="#/app/settings"> - <i class="icon ion-settings"></i> + <i class="icon ion-android-settings"></i> <span translate>MENU.SETTINGS</span> </ion-item> - <ion-item menu-close class="item item-assertive item-icon-left" ng-click="logout()" ng-if="isLogged()"> - <i class="icon ion-log-out"></i> + + <!-- actions --> + <div class="item item-divider" ng-if="isLogged()"></div> + <ion-item menu-close class="item item-button-right" ng-if="isLogged()"> + <span translate>MENU.TRANSFER</span> + <button class="button button-energized-900" ng-click="transfer()"> + <i class="icon ion-paper-airplane"></i> + </button> + </ion-item> + <!-- scan QR code + ion-item menu-close class="item item-button-right" ng-if="isLogged()"> + <span translate>Scan</span> + <button class="button button-energized-900" ng-click="scan()"> + <i class="icon ion-qr-scanner"></i> + </button> + </ion-item--> + <ion-item menu-close class="item item-button-right" ng-if="isLogged()"> <span translate>COMMON.BTN_LOGOUT</span> + <button class="button button-energized-900" ng-click="logout()"> + <i class="icon ion-log-out"></i> + </button> </ion-item> + </ion-list> </ion-content> diff --git a/www/templates/wallet/modal_transfer.html b/www/templates/wallet/modal_transfer.html index 33be62b29..2c2330569 100644 --- a/www/templates/wallet/modal_transfer.html +++ b/www/templates/wallet/modal_transfer.html @@ -1,4 +1,4 @@ -<ion-modal-view id="transfer"> +<ion-view id="transfer" class="modal slide-in-up ng-enter active ng-enter-active"> <ion-header-bar class="bar-positive"> <button class="button button-clear visible-xs" ng-click="closeTransfer()" translate>COMMON.BTN_CANCEL</button> <h1 class="title" translate>TRANSFER.MODAL.TITLE</h1> diff --git a/www/templates/wallet/new_transfer.html b/www/templates/wallet/new_transfer.html index 5bd8b9bb9..ae031d453 100644 --- a/www/templates/wallet/new_transfer.html +++ b/www/templates/wallet/new_transfer.html @@ -1,4 +1,6 @@ -<ion-view view-title="{{'TRANSFER.TITLE' | translate}}" left-buttons="leftButtons"> +<ion-view view-title="{{'TRANSFER.TITLE' | translate}}" + left-buttons="leftButtons" + id="transfer"> <ion-nav-buttons side="secondary"> <button class="button button-icon button-clear icon ion-android-send visible-xs" ng-click="doTransfer()"> </button> diff --git a/www/templates/wallet/transfer_form.html b/www/templates/wallet/transfer_form.html index 543f9ca9b..e6ad5c9b2 100644 --- a/www/templates/wallet/transfer_form.html +++ b/www/templates/wallet/transfer_form.html @@ -7,6 +7,12 @@ <span class="badge badge-royal">{{dest | formatPubkey}}</span> <i class="button button-clear ion-chevron-right"></i> </a> + <div class="form-errors" + ng-show="transferForm.$submitted && !dest"> + <div class="form-error"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + </div> <span class="item item-text-wrap"> <span class="gray" translate>TRANSFER.FROM</span> @@ -20,15 +26,22 @@ <div class="item item-input item-floating-label" ng-if="!formData.useRelative"> <span class="input-label">{{'TRANSFER.AMOUNT' | translate}} ({{unit | abbreviate}}<sub>{{udUnit | abbreviate}}</sub>)</span> - <input type="number" placeholder="{{'TRANSFER.AMOUNT_HELP' | translate}} ({{unit | abbreviate}}{{udUnit | abbreviate}})" + <input type="number" name="amount" placeholder="{{'TRANSFER.AMOUNT_HELP' | translate}} ({{unit | abbreviate}}{{udUnit | abbreviate}})" ng-model="formData.amount" required> </div> <div class="item item-input item-floating-label" ng-if="formData.useRelative"> <span class="input-label">{{'TRANSFER.AMOUNT' | translate}} ({{unit | abbreviate}}<sub>{{udUnit | abbreviate}}</sub>)</span> - <input type="text" placeholder="{{'TRANSFER.AMOUNT_HELP' | translate}} ({{unit | abbreviate}}{{udUnit | abbreviate}})" ng-model="formData.amount" + <input type="text" name="amount" placeholder="{{'TRANSFER.AMOUNT_HELP' | translate}} ({{unit | abbreviate}}{{udUnit | abbreviate}})" ng-model="formData.amount" required> </div> + <div class="form-errors" + ng-show="transferForm.$submitted && transferForm.amount.$error" + ng-messages="transferForm.amount.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + </div> <div class="item item-content item-toggle dark"> @@ -41,9 +54,28 @@ </label> </div> - <label class="item item-input"> - <textarea placeholder="{{'TRANSFER.COMMENTS_HELP' | translate}}" ng-model="formData.comments"></textarea> + <!-- Comment --> + <label class="item item-input" + ng-class="{'item-input-error': transferForm.$submitted && transferForm.comment.$invalid}"> + <textarea placeholder="{{'TRANSFER.COMMENT_HELP' | translate}}" + name="comment" + ng-model="formData.comment" + ng-maxlength="255" + ng-pattern="commentPattern" + > + </textarea> </label> + <div class="form-errors" + ng-show="transferForm.$submitted && transferForm.comment.$error" + ng-messages="transferForm.comment.$error"> + <div class="form-error" ng-message="maxlength"> + <span translate="ERROR.FIELD_TOO_LONG"></span> + </div> + <div class="form-error" ng-message="pattern"> + <span translate="ERROR.FIELD_ACCENT"></span> + </div> + </div> + </div> <div class="padding hidden-xs text-right"> diff --git a/www/templates/wallet/view_wallet.html b/www/templates/wallet/view_wallet.html index 715ec8c92..4870cde52 100644 --- a/www/templates/wallet/view_wallet.html +++ b/www/templates/wallet/view_wallet.html @@ -19,7 +19,7 @@ <div class="avatar" ng-if="!!walletData.avatar" style="background-image: url({{::walletData.avatar}});"></div> - <i class="avatar" ng-class="{'avatar-wallet': !walletData.isMember, 'avatar-member': isMember}" ng-if="!walletData.avatar"></i> + <i class="avatar" ng-class="{'avatar-wallet': !walletData.isMember, 'avatar-member': walletData.isMember}"></i> <h3 class="light" ng-if="walletData.isMember">{{walletData.uid}}</h3> <h3 class="light" ng-if="!walletData.isMember">{{::walletData.pubkey | formatPubkey}}</h3> <h4 class="light"> @@ -30,7 +30,7 @@ </div> <div class="hidden-xs hidden-sm padding" style="text-align:center"> - <button class="button button-raised button-assertive ink-dark" + <button class="button button-raised button-energized-900 ink-dark" ng-click="openTransfer()"> {{'ACCOUNT.BTN_SEND_MONEY' | translate}} </button> -- GitLab