Fixes , merging the signup and login modal into a single modal. Created a couple A/B tests for amount of text in the signup modal.

This commit is contained in:
Scott Erickson 2014-05-22 11:24:35 -07:00
parent d613c230ef
commit bfa90f671d
25 changed files with 216 additions and 249 deletions

View file

@ -77,7 +77,7 @@ module.exports = class CocoRouter extends Backbone.Router
clientid:gplusClientID,
cookiepolicy:"single_host_origin",
scope:"https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email",
size:"medium",
height: "short",
}
if gapi.signin?.render
gapi.signin.render(gplusButton, params)

View file

@ -4,7 +4,8 @@ module.exports.formToObject = (el) ->
inputs = $('input', el).add('textarea', el)
for input in inputs
input = $(input)
obj[input.attr('name')] = input.val()
continue unless name = input.attr('name')
obj[name] = input.val()
obj

View file

@ -79,6 +79,7 @@
sign_up: "Sign Up"
log_in: "log in with password"
social_signup: "Or, you can sign up through Facebook or G+:"
required: "You need to log in before you can go that way."
home:
slogan: "Learn to Code JavaScript by Playing a Game"
@ -400,9 +401,9 @@
new_article_title: "Create a New Article"
new_thang_title: "Create a New Thang Type"
new_level_title: "Create a New Level"
new_article_title_signup: "Sign Up to Create a New Article"
new_thang_title_signup: "Sign Up to Create a New Thang Type"
new_level_title_signup: "Sign Up to Create a New Level"
new_article_title_login: "Log In to Create a New Article"
new_thang_title_login: "Log In to Create a New Thang Type"
new_level_title_login: "Log In to Create a New Level"
article_search_title: "Search Articles Here"
thang_search_title: "Search Thang Types Here"
level_search_title: "Search Levels Here"
@ -536,9 +537,7 @@
introduction_desc_ending: "We hope you'll join our party!"
introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Glen"
alert_account_message_intro: "Hey there!"
alert_account_message_pref: "To subscribe for class emails, you'll need to "
alert_account_message_suf: "first."
alert_account_message_create_url: "create an account"
alert_account_message: "To subscribe for class emails, you'll need to be logged in first."
archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever."
archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever."
class_attributes: "Class Attributes"
@ -675,7 +674,7 @@
warmup: "Warmup"
vs: "VS"
friends_playing: "Friends Playing"
sign_up_for_friends: "Sign up to play with your friends!"
log_in_for_friends: "Log in to play with your friends!"
social_connect_blurb: "Connect and play against your friends!"
invite_friends_to_battle: "Invite your friends to join you in battle!"
fight: "Fight!"

View file

@ -282,3 +282,6 @@ body[lang='ja']
content: " "
.spl:before
content: " "
a[data-toggle="coco-modal"]
cursor: pointer

View file

@ -39,7 +39,7 @@ $brand-primary: #948754 !default;
$brand-success: $green !default;
$brand-warning: $orange !default;
$brand-danger: $red !default;
$brand-info: #f9e811 !default;
$brand-info: $blueDark !default;
// Scaffolding
// -------------------------

View file

@ -0,0 +1,20 @@
#auth-modal
.network-login
float: left
width: 100px
text-align: left
#gplus-login-button
position: relative
top: 1px
#recover-account-wrapper
float: right
.modal-footer
height: 70px
padding: 20px 10px
border-top: 1px solid darkgray
.btn
margin-right: 10px

View file

@ -1,25 +0,0 @@
#login-modal, #signup-modal
.network-logins div
float: left
margin-right: 20px
.wait
margin-bottom: 20px
h3
text-align: center
a[data-toggle="coco-modal"]
cursor: pointer
#signup-modal
.modal-footer
padding-top: 0
div
text-align: center
.social-login-text
padding-top: 20px
.network-logins
width: 263px
margin: 0 auto
div:last-of-type
margin-right: 0px

View file

@ -37,8 +37,10 @@ body
span.glyphicon.glyphicon-user
else
button.btn.btn-primary.navbuttontext.header-font(data-toggle="coco-modal", data-target="modal/signup", data-i18n="login.sign_up") Create Account
button.btn.btn-primary.navbuttontext.header-font(data-toggle="coco-modal", data-target="modal/login", data-i18n="login.log_in") Log In
button.btn.btn-primary.navbuttontext.header-font.auth-button
span(data-i18n="login.log_in") Log In
span.spr.spl /
span(data-i18n="login.sign_up") Create Account
ul(class='navbar-link-text').nav.navbar-nav.pull-right
li.play

View file

@ -80,12 +80,13 @@
hr
if me.get('anonymous')
h1
| Either
a(data-toggle="coco-modal", data-target="modal/signup", data-i18n="login.sign_up") create an account
| or
a(data-toggle="coco-modal", data-target="modal/login", data-i18n="login.log_in") log In
| to sign this agreement.
p
strong You must be signed in to sign this agreement.
button.btn.btn-primary.auth-button
span(data-i18n="login.log_in") Log In
span.spr.spl /
span(data-i18n="login.sign_up") Create Account
else
h3 SIGN HERE

View file

@ -3,10 +3,11 @@ if me.attributes.anonymous
strong(data-i18n="contribute.alert_account_message_intro")
| Hey there!
span
span(data-i18n="contribute.alert_account_message_pref")
| To subscribe for class emails, you'll need to
a(data-toggle="coco-modal", data-target="modal/signup", data-i18n="contribute.alert_account_message_create_url")
| create an account
span
span(data-i18n="contribute.alert_account_message_suf")
| first.
span(data-i18n="contribute.alert_account_message")
| To subscribe for class emails, you'll need to be logged in first.
strong.spl
a.auth-button
span(data-i18n="login.log_in") Log In
span.spr.spl /
span(data-i18n="login.sign_up") Create Account

View file

@ -9,7 +9,7 @@ block content
| #{currentEditor}
if me.get('anonymous')
a.btn.btn-primary.open-modal-button(data-toggle="coco-modal", data-target="modal/signup", role="button", data-i18n="#{currentNewSignup}") Sign Up to Create a New Content
a.btn.btn-primary.open-modal-button(data-toggle="coco-modal", data-target="modal/auth", role="button", data-i18n="#{currentNewSignup}") Log in to Create a New Content
else
a.btn.btn-primary.open-modal-button(href='#new-model-modal', role="button", data-toggle="modal", data-i18n="#{currentNew}") Create a New Something
input#search(data-i18n="[placeholder]#{currentSearch}")

View file

@ -0,0 +1,61 @@
extends /templates/modal/modal_base
block modal-header-content
if mode === 'login'
h3(data-i18n="login.log_in") Log In
if mode === 'signup'
if title === 'short'
h3(data-i18n="login.sign_up") Create Account
else
h3(data-i18n="signup.create_account_title") Create Account to Save Progress
block modal-body-content
if showRequiredError
.alert.alert-success
span(data-i18n="signup.required") You need to log in before you can that way.
else if mode === 'signup' && descriptionOn === "yes"
p(data-i18n="signup.description") It's free. Just need a couple things and you'll be good to go:
form.form
.form-group
label.control-label(for="email", data-i18n="general.email") Email
input#email.input-large.form-control(name="email", type="email", value=formValues.email)
.form-group
label.control-label(for="password", data-i18n="general.password") Password
input#password.input-large.form-control(name="password", type="password", value=formValues.password)
if mode === 'signup'
.form-group.checkbox
label.control-label(for="subscribe")
input#subscribe(name="subscribe", type="checkbox", checked='checked')
span(data-i18n="signup.email_announcements") Receive announcements by email
.form-group.checkbox
label.control-label(for="confirm-age")
input#confirm-age(name="confirm-age", type="checkbox", checked='checked')
span(data-i18n="signup.coppa") 13+ or non-USA
a(href="https://en.wikipedia.org/wiki/Children's_Online_Privacy_Protection_Act", data-i18n="signup.coppa_why", target="_blank") (Why?)
if mode === 'login'
input.btn.btn-info.btn-large#login-button(value=translate("login.log_in"), type="submit")
.btn.btn-default.btn-large#switch-to-signup-button(data-i18n="login.sign_up") Create Account
if mode === 'signup'
input.btn.btn-info.btn-large#signup-button(value=translate("signup.sign_up"), type="submit")
block modal-body-wait-content
if mode === 'login'
h3(data-i18n="login.logging_in") Logging In
if mode === 'signup'
h3(data-i18n="signup.creating") Creating Account...
block modal-footer
.modal-footer
div.network-login
.fb-login-button(data-show-faces="false", data-width="200", data-max-rows="1", data-scope="email")
div.network-login
.gplus-login-button#gplus-login-button
div#recover-account-wrapper
a(data-toggle="coco-modal", data-target="modal/recover", data-i18n="login.recover")#link-to-recover recover account

View file

@ -50,10 +50,10 @@ block modal-footer
br
br
| Already have a CodeCombat account?
a.login-link(data-toggle="coco-modal", data-target="modal/login") Log in to continue!
a.login-link(data-toggle="coco-modal", data-target="modal/auth") Log in to continue!
else
.modal-footer.linkedin
a.login-link(data-toggle="coco-modal", data-target="modal/login") Please log in to continue.
a.login-link(data-toggle="coco-modal", data-target="modal/auth") Please log in to continue.
else if !userIsAnonymous && !userIsAuthorized
.modal-footer.linkedin
else if userIsAuthorized && !userHasSignedContract
@ -61,6 +61,4 @@ block modal-footer
button.btn.btn-primary(id="contract-agreement-button") I agree
else
.modal-footer.linkedin
| Thanks! You've already agreed to the contract.
| Thanks! You've already agreed to the contract.

View file

@ -1,32 +0,0 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="login.log_in") Log In
block modal-body-content
.form
.form-group
label.control-label(for="login-email", data-i18n="general.email") Email
input#login-email.input-large.form-control(name="email", type="email")
.form-group
label.control-label(for="login-password", data-i18n="general.password") Password
input#login-password.input-large.form-control(name="password", type="password")
block modal-body-wait-content
h3(data-i18n="login.logging_in") Logging In
block modal-footer
.modal-footer
button.btn.btn-primary.btn-large#login-button(data-i18n="login.log_in") Log In
.modal-footer.network-logins
div
.fb-login-button(data-show-faces="false", data-width="200", data-max-rows="1", data-scope="email")
div
.gplus-login-button#gplus-login-button
div
a(data-toggle="coco-modal", data-target="modal/signup", data-i18n="login.sign_up")#link-to-signup create new account
span ,
span(data-i18n="general.or") or
span
a(data-toggle="coco-modal", data-target="modal/recover", data-i18n="login.recover")#link-to-recover recover account

View file

@ -1,43 +0,0 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="signup.create_account_title") Create Account to Save Progress
block modal-body-content
if showRequiredError
.alert.alert-success
span(data-i18n="signup.required") You need to sign up first before you can go over there. Luckily, it's really easy.
else
p(data-i18n="signup.description") It's free. Just need a couple things and you'll be good to go:
.form
.form-group
label.control-label(for="signup-email", data-i18n="general.email") Email
input#signup-email.form-control.input-large(name="email", type="email")
.form-group
label.control-label(for="signup-password", data-i18n="general.password") Password
input#signup-password.input-large.form-control(name="password", type="password")
hr
.form-group.checkbox
label.control-label(for="signup-subscribe")
input#signup-subscribe(name="subscribe", type="checkbox", checked='checked')
span(data-i18n="signup.email_announcements") Receive announcements by email
.form-group.checkbox
label.control-label(for="signup-confirm-age")
input#signup-confirm-age(name="confirm-age", type="checkbox", checked='checked')
span(data-i18n="signup.coppa") 13+ or non-USA
a(href="https://en.wikipedia.org/wiki/Children's_Online_Privacy_Protection_Act", data-i18n="signup.coppa_why", target="_blank") (Why?)
block modal-body-wait-content
h3(data-i18n="signup.creating") Creating Account...
block modal-footer
.modal-footer
div
button.btn.btn-primary.btn-large#signup-button(data-i18n="signup.sign_up") Sign Up
div.social-login-text(data-i18n="signup.social_signup") Or, you can sign up through Facebook or G+:
.modal-footer.network-logins
div
.fb-login-button(data-show-faces="false", data-width="200", data-max-rows="1", data-scope="email")
div
.gplus-login-button#gplus-login-button

View file

@ -47,7 +47,7 @@ div#columns.row
h4.friends-header(data-i18n="ladder.friends_playing") Friends Playing
if me.get('anonymous')
div.alert.alert-info
a(data-toggle="coco-modal", data-target="modal/signup", data-i18n="ladder.sign_up_for_friends") Sign up to play with your friends!
a(data-toggle="coco-modal", data-target="modal/auth", data-i18n="ladder.log_in_for_friends") Log in to play with your friends!
else
if !onFacebook || !onGPlus

View file

@ -3,7 +3,7 @@ template = require 'templates/account/settings'
{me} = require('lib/auth')
forms = require('lib/forms')
User = require('models/User')
LoginModalView = require 'views/modal/login_modal'
AuthModalView = require 'views/modal/auth_modal'
WizardSettingsView = require './wizard_settings_view'
JobProfileView = require './job_profile_view'
@ -49,7 +49,7 @@ module.exports = class SettingsView extends View
afterInsert: ->
super()
if me.get('anonymous')
@openModalView new LoginModalView()
@openModalView new AuthModalView()
chooseTab: (category) ->
id = "##{category}-pane"

View file

@ -1,6 +1,5 @@
ContributeClassView = require 'views/contribute/contribute_class_view'
template = require 'templates/contribute/contribute'
SignupModalView = require 'views/modal/signup_modal'
module.exports = class ContributeView extends ContributeClassView
id: "contribute-view"

View file

@ -111,6 +111,7 @@ module.exports = class CocoView extends Backbone.View
context.isMobile = @isMobile()
context.isIE = @isIE()
context.moment = moment
context.translate = $.i18n.t
context
afterRender: ->

View file

@ -17,6 +17,7 @@ module.exports = class RootView extends CocoView
"click #logout-button": "logoutAccount"
'change .language-dropdown': 'onLanguageChanged'
'click .toggle-fullscreen': 'toggleFullscreen'
'click .auth-button': 'onClickAuthbutton'
logoutAccount: ->
logoutUser($('#login-email').val())
@ -26,6 +27,10 @@ module.exports = class RootView extends CocoView
subview = new WizardSettingsModal {}
@openModalView subview
onClickAuthbutton: ->
AuthModal = require 'views/modal/auth_modal'
@openModalView new AuthModal {}
showLoading: ($el) ->
$el ?= @$el.find('.main-content-area')
super($el)

View file

@ -32,17 +32,17 @@ module.exports = class SearchView extends View
when 'Level'
context.currentEditor = 'editor.level_title'
context.currentNew = 'editor.new_level_title'
context.currentNewSignup = 'editor.new_level_title_signup'
context.currentNewSignup = 'editor.new_level_title_login'
context.currentSearch = 'editor.level_search_title'
when 'Thang Type'
context.currentEditor = 'editor.thang_title'
context.currentNew = 'editor.new_thang_title'
context.currentNewSignup = 'editor.new_thang_title_signup'
context.currentNewSignup = 'editor.new_thang_title_login'
context.currentSearch = 'editor.thang_search_title'
when 'Article'
context.currentEditor = 'editor.article_title'
context.currentNew = 'editor.new_article_title'
context.currentNewSignup = 'editor.new_article_title_signup'
context.currentNewSignup = 'editor.new_article_title_login'
context.currentSearch = 'editor.article_search_title'
@$el.i18n()
context

View file

@ -0,0 +1,83 @@
View = require 'views/kinds/ModalView'
template = require 'templates/modal/auth'
{loginUser, createUser, me} = require 'lib/auth'
forms = require 'lib/forms'
User = require 'models/User'
application = require 'application'
module.exports = class AuthModalView extends View
id: "auth-modal"
template: template
mode: 'login' # or 'signup'
events:
# login buttons
"click #switch-to-signup-button": "onSignupInstead"
"click #signup-confirm-age": "checkAge"
'submit': 'onSubmitForm' # handles both submit buttons
subscriptions:
'server-error': 'onServerError'
'logging-in-with-facebook': 'onLoggingInWithFacebook'
getRenderData: ->
c = super()
c.showRequiredError = @options.showRequiredError
c.title = {0: "short", 1: "long"}[me.get('testGroupNumber') % 2]
c.descriptionOn = {0: "yes", 1: "no"}[Math.floor(me.get('testGroupNumber')/2) % 2]
if @mode is 'signup'
application.tracker.identify authModalTitle: c.title
application.tracker.trackEvent 'Started Signup', authModalTitle: c.title, descriptionOn: c.descriptionOn
c.mode = @mode
c.formValues = @previousFormInputs or {}
c
afterInsert: ->
super()
_.delay application.router.renderLoginButtons, 500
onSignupInstead: (e) ->
@mode = 'signup'
@previousFormInputs = forms.formToObject @$el
@render()
_.delay application.router.renderLoginButtons, 500
onSubmitForm: (e) ->
e.preventDefault()
if @mode is 'login' then @loginAccount() else @createAccount()
false
checkAge: (e) ->
$("#signup-button", @$el).prop 'disabled', not $(e.target).prop('checked')
loginAccount: ->
forms.clearFormAlerts(@$el)
userObject = forms.formToObject @$el
res = tv4.validateMultiple userObject, User.schema
return forms.applyErrorsToForm(@$el, res.errors) unless res.valid
@enableModalInProgress(@$el) # TODO: part of forms
loginUser(userObject)
createAccount: ->
forms.clearFormAlerts(@$el)
userObject = forms.formToObject @$el
delete userObject.subscribe
delete userObject["confirm-age"]
for key, val of me.attributes when key in ["preferredLanguage", "testGroupNumber", "dateCreated", "wizardColor1", "name", "music", "volume", "emails"]
userObject[key] ?= val
subscribe = @$el.find('#signup-subscribe').prop('checked')
userObject.emails ?= {}
userObject.emails.generalNews ?= {}
userObject.emails.generalNews.enabled = subscribe
res = tv4.validateMultiple userObject, User.schema
return forms.applyErrorsToForm(@$el, res.errors) unless res.valid
window.tracker?.trackEvent 'Finished Signup'
@enableModalInProgress(@$el)
createUser userObject, null, window.nextLevelURL
onLoggingInWithFacebook: (e) ->
modal = $('.modal:visible', @$el)
@enableModalInProgress(modal) # TODO: part of forms
onServerError: (e) -> # TODO: work error handling into a separate forms system
@disableModalInProgress(@$el)

View file

@ -1,46 +0,0 @@
View = require 'views/kinds/ModalView'
template = require 'templates/modal/login'
{loginUser} = require('lib/auth')
forms = require('lib/forms')
User = require 'models/User'
filterKeyboardEvents = (allowedEvents, func) ->
return (splat...) ->
e = splat[0]
return unless e.keyCode in allowedEvents or not e.keyCode
return func(splat...)
module.exports = class LoginModalView extends View
id: "login-modal"
template: template
events:
"click #login-button": "loginAccount"
"keydown #login-password": "loginAccount"
subscriptions:
'server-error': 'onServerError'
'logging-in-with-facebook': 'onLoggingInWithFacebook'
onServerError: (e) -> # TODO: work error handling into a separate forms system
@disableModalInProgress(@$el)
constructor: (options) ->
@loginAccount = filterKeyboardEvents([13], @loginAccount) # TODO: part of forms
super options
onLoggingInWithFacebook: (e) ->
modal = $('.modal:visible', @$el)
@enableModalInProgress(modal) # TODO: part of forms
loginAccount: (e) =>
forms.clearFormAlerts(@$el)
userObject = forms.formToObject @$el
res = tv4.validateMultiple userObject, User.schema
return forms.applyErrorsToForm(@$el, res.errors) unless res.valid
@enableModalInProgress(@$el) # TODO: part of forms
loginUser(userObject)
afterInsert: ->
super()
application.router.renderLoginButtons()

View file

@ -1,65 +1,4 @@
View = require 'views/kinds/ModalView'
template = require 'templates/modal/signup'
{createUser, me} = require('lib/auth')
forms = require('lib/forms')
User = require 'models/User'
AuthModal = require 'views/modal/auth_modal'
filterKeyboardEvents = (allowedEvents, func) ->
return (splat...) ->
e = splat[0]
return unless e.keyCode in allowedEvents or not e.keyCode
return func(splat...)
module.exports = class SignupModalView extends View
id: "signup-modal"
template: template
events:
"click #signup-confirm-age": "checkAge"
"click #signup-button": "createAccount"
"keydown input": "createAccount"
subscriptions:
'server-error': 'onServerError'
'logging-in-with-facebook': 'onLoggingInWithFacebook'
onServerError: (e) -> # TODO: work error handling into a separate forms system
@disableModalInProgress(@$el)
constructor: (options) ->
@createAccount = filterKeyboardEvents([13], @createAccount) # TODO: part of forms
super options
window.tracker?.trackEvent 'Started Signup'
onLoggingInWithFacebook: (e) ->
modal = $('.modal:visible', @$el)
@enableModalInProgress(modal) # TODO: part of forms
checkAge: (e) ->
$("#signup-button", @$el).prop 'disabled', not $(e.target).prop('checked')
getRenderData: ->
c = super()
c.showRequiredError = @options.showRequiredError
c
createAccount: (e) =>
forms.clearFormAlerts(@$el)
userObject = forms.formToObject @$el
delete userObject.subscribe
delete userObject["confirm-age"]
for key, val of me.attributes when key in ["preferredLanguage", "testGroupNumber", "dateCreated", "wizardColor1", "name", "music", "volume", "emails"]
userObject[key] ?= val
subscribe = @$el.find('#signup-subscribe').prop('checked')
userObject.emails ?= {}
userObject.emails.generalNews ?= {}
userObject.emails.generalNews.enabled = subscribe
res = tv4.validateMultiple userObject, User.schema
return forms.applyErrorsToForm(@$el, res.errors) unless res.valid
window.tracker?.trackEvent 'Finished Signup'
@enableModalInProgress(@$el)
createUser userObject, null, window.nextLevelURL
afterInsert: ->
super()
application.router.renderLoginButtons()
module.exports = class SignupModalView extends AuthModal
mode: 'signup'

View file

@ -92,7 +92,7 @@ module.exports = class LadderView extends RootView
@openModalView modal
showApologeticSignupModal: ->
SignupModal = require 'views/modal/signup_modal'
SignupModal = require 'views/modal/auth_modal'
@openModalView(new SignupModal({showRequiredError:true}))
onClickedLink: (e) ->