Browse Source

Improved login form

Added country selector
Added phone number confirmation
master
Igor Zhukov 11 years ago
parent
commit
5eac2f5055
  1. 95
      app/css/app.css
  2. 160
      app/js/controllers.js
  3. 43
      app/js/directives.js
  4. 3
      app/js/lib/config.js
  5. 4
      app/js/services.js
  6. 5
      app/partials/confirm_modal.html
  7. 40
      app/partials/country_select_modal.html
  8. 22
      app/partials/login.html

95
app/css/app.css

@ -449,6 +449,11 @@ input[type="number"]::-webkit-inner-spin-button {
.modal-body { .modal-body {
padding: 14px 14px; padding: 14px 14px;
} }
.modal_simple_header {
font-size: 14px;
margin: 0 0 12px;
text-align: center;
}
.modal_simple_form { .modal_simple_form {
max-width: 230px; max-width: 230px;
@ -691,6 +696,35 @@ a.tg_radio_on:hover i.icon-radio {
font-size: 13px; font-size: 13px;
} }
.login_country_selector {
cursor: pointer;
background: #f7f7f7;
height: 34px;
padding: 10px 12px 10px 13px;
line-height: 14px;
margin-bottom: 12px;
}
.login_country_selector .icon-caret {
margin-top: 4px;
}
.login_phone_country,
.login_phone_number {
float: left;
display: inline-block;
width: auto;
font-size: 12px;
}
.login_phone_country {
width: 53px;
margin-right: 9px;
padding: 6px 3px;
text-align: center;
}
.login_phone_number {
width: 198px;
}
/* IM page start */ /* IM page start */
@ -2306,6 +2340,12 @@ img.chat_modal_participant_photo {
margin-top: 40px; margin-top: 40px;
} }
.confirm_phone_number {
font-weight: bold;
padding: 15px 10px 0;
text-align: center;
}
.photo_modal_error { .photo_modal_error {
@ -3024,6 +3064,61 @@ ce671b orange
} }
.countries_modal_window .modal-dialog {
max-width: 392px;
}
.countries_modal_search {
padding: 0 20px 12px;
margin: 0;
}
.countries_modal_wrap .modal-body {
padding: 14px 0;
}
.countries_modal_col .nano > .pane {
background : rgba(3,36,64,0.08);
width : 3px;
right: 6px;
top: 0;
-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
transition : .2s;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.countries_modal_col .nano > .pane > .slider {
background : rgba(3,46,79,0.22);
margin: 0;
-moz-border-radius : 0;
-webkit-border-radius : 0;
border-radius : 0;
}
.countries_scrollable_wrap a.countries_modal_country {
clear: both;
overflow: hidden;
color: #000;
padding: 8px 26px;
font-size: 12px;
border-radius: 0;
}
.countries_scrollable_wrap a.countries_modal_country:hover {
border-radius: 2px;
background: #f2f6fa;
}
.countries_modal_country_code {
color: #999;
}
.countries_scrollable_wrap a.countries_modal_country:hover .countries_modal_country_code {
color: #698192;
}
/* Loading dots animation */ /* Loading dots animation */
.loading_dots .loading_dots

160
app/js/controllers.js

@ -21,7 +21,7 @@ angular.module('myApp.controllers', [])
}); });
}) })
.controller('AppLoginController', function ($scope, $location, $timeout, MtpApiManager, ErrorService) { .controller('AppLoginController', function ($scope, $location, $timeout, $modal, MtpApiManager, ErrorService) {
MtpApiManager.getUserID().then(function (id) { MtpApiManager.getUserID().then(function (id) {
if (id) { if (id) {
$location.url('/im'); $location.url('/im');
@ -30,10 +30,51 @@ angular.module('myApp.controllers', [])
}); });
var options = {dcID: 1, createNetworker: true}; var options = {dcID: 1, createNetworker: true};
$scope.credentials = {}; $scope.credentials = {phone_country: '+1', phone_country_name: 'USA', phone_number: '', phone_full: ''};
$scope.progress = {}; $scope.progress = {};
$scope.callPending = {}; $scope.callPending = {};
$scope.selectCountry = function () {
var modal = $modal.open({
templateUrl: 'partials/country_select_modal.html',
controller: 'CountrySelectModalController',
windowClass: 'countries_modal_window'
});
modal.result.then(function (code) {
$scope.credentials.phone_country = code;
$scope.$broadcast('country_selected');
});
};
$scope.$watch('credentials.phone_country', updateCountry);
$scope.$watch('credentials.phone_number', updateCountry);
function updateCountry () {
var phoneNumber = (
($scope.credentials.phone_country || '') +
($scope.credentials.phone_number || '')
).replace(/\D+/g, ''),
i, j, code,
maxLength = 0,
maxName = false;
if (phoneNumber.length) {
for (i = 0; i < Config.CountryCodes.length; i++) {
for (j = 1; j < Config.CountryCodes[i].length; j++) {
code = Config.CountryCodes[i][j].replace(/\D+/g, '');
if (code.length >= maxLength && !phoneNumber.indexOf(code)) {
maxLength = code.length;
maxName = Config.CountryCodes[i][0];
}
}
}
}
$scope.credentials.phone_full = phoneNumber;
$scope.credentials.phone_country_name = maxName || 'Unknown';
};
var callTimeout; var callTimeout;
function saveAuth (result) { function saveAuth (result) {
@ -51,7 +92,7 @@ angular.module('myApp.controllers', [])
if (!(--$scope.callPending.remaining)) { if (!(--$scope.callPending.remaining)) {
$scope.callPending.success = false; $scope.callPending.success = false;
MtpApiManager.invokeApi('auth.sendCall', { MtpApiManager.invokeApi('auth.sendCall', {
phone_number: $scope.credentials.phone_number, phone_number: $scope.credentials.phone_full,
phone_code_hash: $scope.credentials.phone_code_hash phone_code_hash: $scope.credentials.phone_code_hash
}, options).then(function () { }, options).then(function () {
$scope.callPending.success = true; $scope.callPending.success = true;
@ -63,38 +104,53 @@ angular.module('myApp.controllers', [])
$scope.sendCode = function () { $scope.sendCode = function () {
$timeout.cancel(callTimeout); $timeout.cancel(callTimeout);
$scope.progress.enabled = true;
MtpApiManager.invokeApi('auth.checkPhone', {
phone_number: $scope.credentials.phone_number
}, options).then(function (result) {
$scope.progress.enabled = false;
if (!result.phone_registered) {
ErrorService.show({
error: {code: 400, type: 'ACCOUNT_REQUIRED'},
phone: $scope.credentials.phone_number
});
return false;
}
ErrorService.confirm({
type: 'LOGIN_PHONE_CORRECT',
country_code: $scope.credentials.phone_country,
phone_number: $scope.credentials.phone_number
}).then(function () {
$scope.progress.enabled = true; $scope.progress.enabled = true;
MtpApiManager.invokeApi('auth.sendCode', { MtpApiManager.invokeApi('auth.checkPhone', {
phone_number: $scope.credentials.phone_number, phone_number: $scope.credentials.phone_full
sms_type: 0, }, options).then(function (result) {
api_id: 2496,
api_hash: '8da85b0d5bfe62527e5b244c209159c3'
}, options).then(function (sentCode) {
$scope.progress.enabled = false; $scope.progress.enabled = false;
if (!result.phone_registered) {
ErrorService.show({
error: {code: 400, type: 'ACCOUNT_REQUIRED'},
phone: $scope.credentials.phone_full
});
return false;
}
$scope.credentials.phone_code_hash = sentCode.phone_code_hash; $scope.progress.enabled = true;
$scope.credentials.phone_occupied = sentCode.phone_registered; MtpApiManager.invokeApi('auth.sendCode', {
$scope.error = {}; phone_number: $scope.credentials.phone_full,
sms_type: 0,
$scope.callPending.remaining = sentCode.send_call_timeout; api_id: 2496,
callCheck(); api_hash: '8da85b0d5bfe62527e5b244c209159c3'
}, options).then(function (sentCode) {
$scope.progress.enabled = false;
$scope.credentials.phone_code_hash = sentCode.phone_code_hash;
$scope.credentials.phone_occupied = sentCode.phone_registered;
$scope.error = {};
$scope.callPending.remaining = sentCode.send_call_timeout;
callCheck();
}, function (error) {
$scope.progress.enabled = false;
console.log('sendCode error', error);
switch (error.type) {
case 'PHONE_NUMBER_INVALID':
$scope.error = {field: 'phone'};
error.handled = true;
break;
}
});
}, function (error) { }, function (error) {
$scope.progress.enabled = false; $scope.progress.enabled = false;
console.log('sendCode error', error);
switch (error.type) { switch (error.type) {
case 'PHONE_NUMBER_INVALID': case 'PHONE_NUMBER_INVALID':
$scope.error = {field: 'phone'}; $scope.error = {field: 'phone'};
@ -102,20 +158,14 @@ angular.module('myApp.controllers', [])
break; break;
} }
}); });
}, function (error) {
$scope.progress.enabled = false;
switch (error.type) {
case 'PHONE_NUMBER_INVALID':
$scope.error = {field: 'phone'};
error.handled = true;
break;
}
}); });
} }
$scope.logIn = function (forceSignUp) { $scope.logIn = function (forceSignUp) {
var method = 'auth.signIn', params = { var method = 'auth.signIn', params = {
phone_number: $scope.credentials.phone_number, phone_number: $scope.credentials.phone_full,
phone_code_hash: $scope.credentials.phone_code_hash, phone_code_hash: $scope.credentials.phone_code_hash,
phone_code: $scope.credentials.phone_code phone_code: $scope.credentials.phone_code
}; };
@ -1629,3 +1679,37 @@ angular.module('myApp.controllers', [])
}; };
}) })
.controller('CountrySelectModalController', function ($scope, $modalInstance, $rootScope, SearchIndexManager) {
$scope.search = {};
var searchIndex = SearchIndexManager.createIndex();
for (var i = 0; i < Config.CountryCodes.length; i++) {
SearchIndexManager.indexObject(i, Config.CountryCodes[i].join(' '), searchIndex);
}
$scope.$watch('search.query', function (newValue) {
var filtered = false,
results = {};
if (angular.isString(newValue) && newValue.length) {
filtered = true;
results = SearchIndexManager.search(newValue, searchIndex);
}
console.log(dT(), newValue, results);
$scope.countries = [];
var j;
for (var i = 0; i < Config.CountryCodes.length; i++) {
if (!filtered || results[i]) {
for (j = 1; j < Config.CountryCodes[i].length; j++) {
$scope.countries.push({name: Config.CountryCodes[i][0], code: Config.CountryCodes[i][j]});
}
}
}
});
})

43
app/js/directives.js

@ -149,6 +149,37 @@ angular.module('myApp.directives', ['myApp.filters'])
}) })
.directive('myCountriesList', function($window, $timeout) {
return {
link: link
};
function link ($scope, element, attrs) {
var searchWrap = $('.countries_modal_search')[0],
panelWrap = $('.countries_modal_panel')[0],
countriesWrap = $('.countries_wrap', element)[0];
onContentLoaded(function () {
$(countriesWrap).nanoScroller({preventPageScrolling: true, tabIndex: -1, iOSNativeScrolling: true});
updateSizes();
});
function updateSizes () {
$(element).css({
height: $($window).height() - (panelWrap && panelWrap.offsetHeight || 0) - (searchWrap && searchWrap.offsetHeight || 0) - 200
});
$(countriesWrap).nanoScroller();
}
$($window).on('resize', updateSizes);
$scope.$on('contacts_change', function () {
onContentLoaded(updateSizes)
});
};
})
.directive('myHistory', function ($window, $timeout, $transition) { .directive('myHistory', function ($window, $timeout, $transition) {
return { return {
@ -972,6 +1003,18 @@ angular.module('myApp.directives', ['myApp.filters'])
}; };
}) })
.directive('myFocusOn', function(){
return {
link: function($scope, element, attrs) {
$scope.$on(attrs.myFocusOn, function () {
onContentLoaded(function () {
element[0].focus();
});
});
}
};
})
.directive('myFileUpload', function(){ .directive('myFileUpload', function(){
return { return {

3
app/js/lib/config.js

File diff suppressed because one or more lines are too long

4
app/js/services.js

@ -564,7 +564,7 @@ angular.module('myApp.services', [])
var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g, var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g,
trimRe = /^\s+|\s$/g, trimRe = /^\s+|\s$/g,
accentsReplace = { accentsReplace = {
a: /[áâäà]/g, a: /[åáâäà]/g,
e: /[éêëè]/g, e: /[éêëè]/g,
i: /[íîïì]/g, i: /[íîïì]/g,
o: /[óôöò]/g, o: /[óôöò]/g,
@ -3252,7 +3252,7 @@ angular.module('myApp.services', [])
if (typeof params === 'string') { if (typeof params === 'string') {
params = {message: params}; params = {message: params};
} }
confirm(params).then(function (result) { confirm(params.message).then(function (result) {
callback(result || true) callback(result || true)
}, function () { }, function () {
callback(false) callback(false)

5
app/partials/confirm_modal.html

@ -16,6 +16,10 @@
</span> </span>
<span ng-switch-when="FILE_CLIPBOARD_PASTE">Are you sure to send file(s) from clipboard?</span> <span ng-switch-when="FILE_CLIPBOARD_PASTE">Are you sure to send file(s) from clipboard?</span>
<span ng-switch-when="MESSAGE_DELETE">Are you sure to delete the message?</span> <span ng-switch-when="MESSAGE_DELETE">Are you sure to delete the message?</span>
<div ng-switch-when="LOGIN_PHONE_CORRECT">
Is this phone number correct?
<div class="confirm_phone_number"> <span ng-bind="country_code"></span> <span ng-bind="phone_number"></span> </div>
</div>
<span ng-switch-default ng-bind="message || 'Are you sure?'"></span> <span ng-switch-default ng-bind="message || 'Are you sure?'"></span>
</div> </div>
@ -31,6 +35,7 @@
<span ng-switch-when="FILES_CLIPBOARD_PASTE">Send</span> <span ng-switch-when="FILES_CLIPBOARD_PASTE">Send</span>
<span ng-switch-when="FILE_CLIPBOARD_PASTE">Send</span> <span ng-switch-when="FILE_CLIPBOARD_PASTE">Send</span>
<span ng-switch-when="MESSAGE_DELETE">Delete</span> <span ng-switch-when="MESSAGE_DELETE">Delete</span>
<span ng-switch-when="LOGIN_PHONE_CORRECT">Yes</span>
<span ng-switch-default>OK</span> <span ng-switch-default>OK</span>
</button> </button>
</div> </div>

40
app/partials/country_select_modal.html

@ -0,0 +1,40 @@
<div class="countries_modal_wrap" my-modal-position>
<div class="modal-body">
<h4 class="modal_simple_header">Country</h4>
<div class="countries_modal_search">
<input class="form-control countries_modal_search_field" my-focused type="search" placeholder="Search" ng-model="search.query"/>
<a class="countries_modal_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div>
<div class="countries_modal_col" my-countries-list>
<div class="countries_wrap nano">
<div class="countries_scrollable_wrap content">
<ul class="countries_modal_members_list nav nav-pills nav-stacked">
<li class="countries_modal_country_wrap clearfix" ng-repeat="country in countries track by $index">
<a class="countries_modal_country" ng-click="$close(country.code)">
<span class="countries_modal_country_code pull-right" ng-bind="country.code"></span>
<span class="countries_modal_country_name" ng-bind="country.name"></span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<a class="btn btn-link" ng-click="$dismiss()">Cancel</a>
<button type="button" class="btn btn-primary" ng-click="$dismiss()">Done</button>
</div>
</div>

22
app/partials/login.html

@ -5,14 +5,21 @@
<div class="error" ng-if="error.message">{{ error.message }}</div> <div class="error" ng-if="error.message">{{ error.message }}</div>
<form name="mySendCodeForm" ng-if="!credentials.phone_code_hash" ng-submit="sendCode()"> <form name="mySendCodeForm" ng-if="!credentials.phone_code_hash" ng-submit="sendCode()">
<h3 class="login_form_head">Sign in</h3> <h3 class="login_form_head">Sign in</h3>
<p class="login_form_lead">Please enter your full phone number with country code.</p> <p class="login_form_lead">Please choose your country and enter your full phone number.</p>
<div class="form-group" ng-class="{'has-error': error.field == 'phone'}"> <div class="login_country_selector" ng-click="selectCountry()">
<span ng-bind="credentials.phone_country_name"></span>
<i class="icon icon-caret pull-right"></i>
</div>
<div class="form-group clearfix" ng-class="{'has-error': error.field == 'phone'}">
<label class="control-label" for="phone_number" ng-if="error.field == 'phone'">Incorrect phone number</label> <label class="control-label" for="phone_number" ng-if="error.field == 'phone'">Incorrect phone number</label>
<input type="tel" class="form-control" my-focused name="phone_number" ng-model="credentials.phone_number" placeholder="Enter your phone" required> <input type="tel" class="form-control pull-left login_phone_country" my-focused name="phone_country" ng-model="credentials.phone_country">
<input type="tel" class="form-control pull-left login_phone_number" my-focus-on="country_selected" name="phone_number" ng-model="credentials.phone_number" placeholder="Enter your phone" required>
</div> </div>
<button class="btn btn-success btn-block" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled" type="submit"> <button class="btn btn-primary btn-block" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled" type="submit" ng-switch="progress.enabled">
{{progress.enabled ? 'Generating keys...' : 'Next'}} <span ng-switch-when="true">Generating keys<span my-loading-dots></span></span>
<span ng-switch-default>Next</span>
</button> </button>
</form> </form>
@ -31,8 +38,9 @@
<input type="number" my-focused maxlength="5" class="form-control" name="phone_code" ng-model="credentials.phone_code" placeholder="Enter your code" required> <input type="number" my-focused maxlength="5" class="form-control" name="phone_code" ng-model="credentials.phone_code" placeholder="Enter your code" required>
</div> </div>
<button class="btn btn-success btn-block" type="submit" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled"> <button class="btn btn-primary btn-block" type="submit" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled" ng-switch="progress.enabled">
{{progress.enabled ? 'Checking code...' : 'Sign in'}} <span ng-switch-when="true">Checking code<span my-loading-dots></span></span>
<span ng-switch-default>Next</span>
</button> </button>
</form> </form>
</div> </div>

Loading…
Cancel
Save