Skip to content
Snippets Groups Projects
Commit 4ecdcf96 authored by Shane Tomlinson's avatar Shane Tomlinson
Browse files

Usability improvements of the signup page.

* If the user types in a known secondary, redirect the user to the signin page.
* If the user manually clicks the "new to persona?" or "Existing account?" links, clear the stored email address.
parent 9751db18
No related branches found
No related tags found
No related merge requests found
...@@ -149,6 +149,10 @@ BrowserID.signIn = (function() { ...@@ -149,6 +149,10 @@ BrowserID.signIn = (function() {
self.bind("#email", "change", onEmailChange); self.bind("#email", "change", onEmailChange);
self.bind("#email", "keyup", onEmailChange); self.bind("#email", "keyup", onEmailChange);
// a redirect to the signup page using the link needs to clear the stored
// email address or else the user may be redirected here.
self.bind(".redirect", "click", pageHelpers.clearStoredEmail);
sc.start.call(self, options); sc.start.call(self, options);
// If there is an email already set up in pageHelpers.setupEmail, see if // If there is an email already set up in pageHelpers.setupEmail, see if
......
...@@ -15,10 +15,13 @@ BrowserID.signUp = (function() { ...@@ -15,10 +15,13 @@ BrowserID.signUp = (function() {
validation = bid.Validation, validation = bid.Validation,
errors = bid.Errors, errors = bid.Errors,
tooltip = BrowserID.Tooltip, tooltip = BrowserID.Tooltip,
complete = helpers.complete,
ANIMATION_SPEED = 250, ANIMATION_SPEED = 250,
storedEmail = pageHelpers, storedEmail = pageHelpers,
winchan = window.WinChan, winchan = window.WinChan,
doc = document,
primaryUserInfo, primaryUserInfo,
lastEmail,
sc; sc;
function showNotice(selector) { function showNotice(selector) {
...@@ -28,7 +31,7 @@ BrowserID.signUp = (function() { ...@@ -28,7 +31,7 @@ BrowserID.signUp = (function() {
function authWithPrimary(oncomplete) { function authWithPrimary(oncomplete) {
pageHelpers.openPrimaryAuth(winchan, primaryUserInfo.email, primaryUserInfo.auth, primaryAuthComplete); pageHelpers.openPrimaryAuth(winchan, primaryUserInfo.email, primaryUserInfo.auth, primaryAuthComplete);
oncomplete && oncomplete(); complete(oncomplete);
} }
function primaryAuthComplete(error, result, oncomplete) { function primaryAuthComplete(error, result, oncomplete) {
...@@ -42,19 +45,15 @@ BrowserID.signUp = (function() { ...@@ -42,19 +45,15 @@ BrowserID.signUp = (function() {
} }
function createPrimaryUser(info, oncomplete) { function createPrimaryUser(info, oncomplete) {
function complete(status) {
oncomplete && oncomplete(status);
}
user.createPrimaryUser(info, function onComplete(status, info) { user.createPrimaryUser(info, function onComplete(status, info) {
switch(status) { switch(status) {
case "primary.verified": case "primary.verified":
pageHelpers.replaceFormWithNotice("#congrats", complete.bind(null, true)); pageHelpers.replaceFormWithNotice("#congrats", complete.curry(oncomplete, true));
break; break;
case "primary.verify": case "primary.verify":
primaryUserInfo = info; primaryUserInfo = info;
dom.setInner("#primary_email", info.email); dom.setInner("#primary_email", info.email);
pageHelpers.replaceInputsWithNotice("#primary_verify", complete.bind(null, false)); pageHelpers.replaceInputsWithNotice("#primary_verify", complete.curry(oncomplete, false));
break; break;
case "primary.could_not_add": case "primary.could_not_add":
// XXX Can this happen? // XXX Can this happen?
...@@ -66,14 +65,17 @@ BrowserID.signUp = (function() { ...@@ -66,14 +65,17 @@ BrowserID.signUp = (function() {
} }
function enterPasswordState(info) { function enterPasswordState(info) {
/*jshint validthis: true*/
var self=this; var self=this;
self.emailToStage = info.email; self.emailToStage = info.email;
self.submit = passwordSubmit; self.submit = passwordSubmit;
dom.addClass("body", "enter_password"); dom.addClass("body", "enter_password");
dom.focus("#password");
} }
function passwordSubmit(oncomplete) { function passwordSubmit(oncomplete) {
/*jshint validthis: true*/
var pass = dom.getInner("#password"), var pass = dom.getInner("#password"),
vpass = dom.getInner("#vpassword"), vpass = dom.getInner("#vpassword"),
valid = validation.passwordAndValidationPassword(pass, vpass); valid = validation.passwordAndValidationPassword(pass, vpass);
...@@ -85,44 +87,42 @@ BrowserID.signUp = (function() { ...@@ -85,44 +87,42 @@ BrowserID.signUp = (function() {
} }
else { else {
tooltip.showTooltip("#could_not_add"); tooltip.showTooltip("#could_not_add");
oncomplete && oncomplete(false); complete(oncomplete, false);
} }
}, pageHelpers.getFailure(errors.createUser, oncomplete)); }, pageHelpers.getFailure(errors.createUser, oncomplete));
} }
else { else {
oncomplete && oncomplete(false); complete(oncomplete, false);
} }
} }
function emailSubmit(oncomplete) { function emailSubmit(oncomplete) {
/*jshint validthis: true*/
var email = helpers.getAndValidateEmail("#email"), var email = helpers.getAndValidateEmail("#email"),
self = this; self = this;
if (email) { if (email) {
dom.setAttr('#email', 'disabled', 'disabled'); dom.setAttr('#email', 'disabled', 'disabled');
user.isEmailRegistered(email, function(isRegistered) { user.addressInfo(email, function(info) {
if(isRegistered) { dom.removeAttr('#email', 'disabled');
dom.removeAttr('#email', 'disabled');
$('#registeredEmail').html(email); var known = info.known;
showNotice(".alreadyRegistered");
oncomplete && oncomplete(false); if(info.type === "secondary" && known) {
doc.location = "/signin";
complete(oncomplete, false);
} }
else { else if(info.type === "secondary" && !known) {
user.addressInfo(email, function(info) { enterPasswordState.call(self, info);
dom.removeAttr('#email', 'disabled'); complete(oncomplete, !known);
if(info.type === "primary") { }
createPrimaryUser.call(self, info, oncomplete); else if(info.type === "primary") {
} createPrimaryUser.call(self, info, oncomplete);
else {
enterPasswordState.call(self, info);
oncomplete && oncomplete(!isRegistered);
}
}, pageHelpers.getFailure(errors.addressInfo, oncomplete));
} }
}, pageHelpers.getFailure(errors.isEmailRegistered, oncomplete)); }, pageHelpers.getFailure(errors.addressInfo, oncomplete));
} }
else { else {
oncomplete && oncomplete(false); complete(oncomplete, false);
} }
} }
...@@ -130,8 +130,16 @@ BrowserID.signUp = (function() { ...@@ -130,8 +130,16 @@ BrowserID.signUp = (function() {
pageHelpers.cancelEmailSent(oncomplete); pageHelpers.cancelEmailSent(oncomplete);
} }
function onEmailKeyUp(event) { function onEmailChange(event) {
if (event.which !== 13) $(".notification").fadeOut(ANIMATION_SPEED); /*jshint validthis: true*/
// this is basically a state reset.
var email = dom.getInner("#email");
if(email !== lastEmail) {
dom.removeClass("body", "enter_password");
this.submit = emailSubmit;
lastEmail = email;
}
} }
var Module = bid.Modules.PageModule.extend({ var Module = bid.Modules.PageModule.extend({
...@@ -139,19 +147,33 @@ BrowserID.signUp = (function() { ...@@ -139,19 +147,33 @@ BrowserID.signUp = (function() {
var self=this; var self=this;
options = options || {}; options = options || {};
if (options.winchan) { if (options.winchan) winchan = options.winchan;
winchan = options.winchan; if (options.document) doc = options.document;
}
dom.focus("form input[autofocus]"); dom.focus("form input[autofocus]");
pageHelpers.setupEmail(); pageHelpers.setupEmail();
self.bind("#email", "keyup", onEmailKeyUp); self.bind("#email", "keyup", onEmailChange);
self.bind("#email", "change", onEmailChange);
self.click("#back", back); self.click("#back", back);
self.click("#authWithPrimary", authWithPrimary); self.click("#authWithPrimary", authWithPrimary);
// a redirect to the signin page using the link needs to clear
// the stored email address or else the user may be redirected here.
self.bind(".redirect", "click", pageHelpers.clearStoredEmail);
sc.start.call(self, options); sc.start.call(self, options);
// If there is an email already set up in pageHelpers.setupEmail,
// see if the email address is a primary, secondary, known or
// unknown. Redirect if needed.
if (dom.getInner("#email")) {
self.submit(options.ready);
}
else {
complete(options.ready);
}
}, },
submit: emailSubmit, submit: emailSubmit,
......
/*jshint browser: true, forin: true, laxbreak: true */ /*jshint browser: true, forin: true, laxbreak: true */
/*global test: true, start: true, module: true, ok: true, equal: true, BrowserID:true */ /*global test: true, start: true, module: true, ok: true, equal: true, BrowserID:true, strictEqual */
/* This Source Code Form is subject to the terms of the Mozilla Public /* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
...@@ -11,22 +11,38 @@ ...@@ -11,22 +11,38 @@
network = bid.Network, network = bid.Network,
xhr = bid.Mocks.xhr, xhr = bid.Mocks.xhr,
WinChanMock = bid.Mocks.WinChan, WinChanMock = bid.Mocks.WinChan,
WindowMock = bid.Mocks.WindowMock,
testHelpers = bid.TestHelpers, testHelpers = bid.TestHelpers,
testDocumentRedirected = testHelpers.testDocumentRedirected,
testDocumentNotRedirected = testHelpers.testDocumentNotRedirected,
testHasClass = testHelpers.testHasClass,
pageHelpers = bid.PageHelpers,
provisioning = bid.Mocks.Provisioning, provisioning = bid.Mocks.Provisioning,
winchan, winchan,
docMock,
controller; controller;
function createController(options) {
winchan = new WinChanMock();
docMock = new WindowMock().document;
options = options || {};
_.extend(options, {
document: docMock,
winchan: winchan
});
controller = bid.signUp.create();
controller.start(options);
}
module("pages/js/signup", { module("pages/js/signup", {
setup: function() { setup: function() {
testHelpers.setup(); testHelpers.setup();
bid.Renderer.render("#page_head", "site/signup", {}); bid.Renderer.render("#page_head", "site/signup", {});
$(".emailsent").hide(); $(".emailsent").hide();
$(".notification").hide() $(".notification").hide();
winchan = new WinChanMock(); createController();
controller = bid.signUp.create();
controller.start({
winchan: winchan
});
}, },
teardown: function() { teardown: function() {
testHelpers.teardown(); testHelpers.teardown();
...@@ -45,11 +61,59 @@ ...@@ -45,11 +61,59 @@
}); });
} }
asyncTest("start with no email stored - nothing fancy", function() {
createController({
ready: function() {
testDocumentNotRedirected(docMock, "user not signed in");
start();
}
});
});
asyncTest("start with unknown secondary email stored - show password fields", function() {
xhr.useResult("unknown_secondary");
pageHelpers.setStoredEmail("unregistered@testuser.com");
createController({
ready: function() {
start();
testHasClass("body", "enter_password", "enter_password class added to body");
testDocumentNotRedirected(docMock);
}
});
});
asyncTest("start with known secondary email stored - redirect to /signin", function() {
xhr.useResult("known_secondary");
pageHelpers.setStoredEmail("registered@testuser.com");
createController({
ready: function() {
testDocumentRedirected(docMock, "/signin", "user sent to /signin page");
start();
}
});
});
/*
asyncTest("start with known primary email stored - show verify primary", function() {
xhr.useResult("primary");
provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
pageHelpers.setStoredEmail("registered@testuser.com");
createController({
ready: function() {
testHasClass("body", "verify_primary", "verify_primary class added to body");
testDocumentNotRedirected(docMock);
start();
}
});
});
*/
asyncTest("signup with valid unregistered secondary email - show password", function() { asyncTest("signup with valid unregistered secondary email - show password", function() {
$("#email").val("unregistered@testuser.com"); $("#email").val("unregistered@testuser.com");
controller.submit(function() { controller.submit(function() {
equal($("body").hasClass("enter_password"), true, "new email, password section shown"); testHasClass("body", "enter_password", "new email, password section shown");
start(); start();
}); });
...@@ -60,7 +124,7 @@ ...@@ -60,7 +124,7 @@
$("#email").val(" unregistered@testuser.com "); $("#email").val(" unregistered@testuser.com ");
controller.submit(function() { controller.submit(function() {
equal($("body").hasClass("enter_password"), true, "new email, password section shown"); testHasClass("body", "enter_password", "new email, password section shown");
start(); start();
}); });
}); });
...@@ -146,6 +210,7 @@ ...@@ -146,6 +210,7 @@
asyncTest("signup with primary email address, user must verify with primary", function() { asyncTest("signup with primary email address, user must verify with primary", function() {
xhr.useResult("primary"); xhr.useResult("primary");
provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
$("#email").val("unregistered@testuser.com"); $("#email").val("unregistered@testuser.com");
controller.submit(function(status) { controller.submit(function(status) {
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
<div class="submit cf forminputs"> <div class="submit cf forminputs">
<button tabindex="5"><%- gettext('Sign In') %></button> <button tabindex="5"><%- gettext('Sign In') %></button>
<div class="remember cf"> <div class="remember cf">
<a class="action" href="/signup"><%- gettext('New to Persona? Sign up today.') %></a> <a class="action redirect" href="/signup"><%- gettext('New to Persona? Sign up today.') %></a>
</div> </div>
</div> </div>
......
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
<div class="submit cf forminputs"> <div class="submit cf forminputs">
<p class="cf"> <p class="cf">
<button><%- gettext('Verify Email') %></button> <button><%- gettext('Verify Email') %></button>
<a class="action remember" href="/signin" tabindex="2"><%- gettext('Existing account? Sign in.') %></a> <a class="action remember redirect" href="/signin" tabindex="2"><%- gettext('Existing account? Sign in.') %></a>
</p> </p>
<p class="tospp"> <p class="tospp">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment