Update request demo Ux

Renaming request quote to request demo
Changing create class wording to set up class
Showing different UI if teacher or not
Adding gameplay screenshots to homepage
Update request demo email

Closes 
This commit is contained in:
Matt Lott 2016-03-04 12:05:07 -08:00
parent ee331cc9c5
commit bce9862be2
11 changed files with 195 additions and 45 deletions

Binary file not shown.

After

(image error) Size: 108 KiB

View file

@ -133,6 +133,7 @@ module.exports = class CocoRouter extends Backbone.Router
'teachers': go('NewHomeView') 'teachers': go('NewHomeView')
'teachers/freetrial': go('RequestQuoteView') 'teachers/freetrial': go('RequestQuoteView')
'teachers/quote': go('RequestQuoteView') 'teachers/quote': go('RequestQuoteView')
'teachers/demo': go('RequestQuoteView')
'test(/*subpath)': go('TestView') 'test(/*subpath)': go('TestView')

View file

@ -70,7 +70,7 @@ module.exports = class Tracker extends CocoClass
for userTrait in ['email', 'anonymous', 'dateCreated', 'name', 'testGroupNumber', 'gender', 'lastLevel', 'siteref', 'ageRange', 'schoolName', 'coursePrepaidID', 'role'] for userTrait in ['email', 'anonymous', 'dateCreated', 'name', 'testGroupNumber', 'gender', 'lastLevel', 'siteref', 'ageRange', 'schoolName', 'coursePrepaidID', 'role']
traits[userTrait] ?= me.get(userTrait) traits[userTrait] ?= me.get(userTrait)
if @isTeacher() if me.isTeacher()
traits.teacher = true traits.teacher = true
console.log 'Would identify', me.id, traits if debugAnalytics console.log 'Would identify', me.id, traits if debugAnalytics
@ -90,7 +90,7 @@ module.exports = class Tracker extends CocoClass
mixpanel.identify(me.id) mixpanel.identify(me.id)
mixpanel.register(traits) mixpanel.register(traits)
if @isTeacher() and @segmentLoaded if me.isTeacher() and @segmentLoaded
traits.createdAt = me.get 'dateCreated' # Intercom, at least, wants this traits.createdAt = me.get 'dateCreated' # Intercom, at least, wants this
analytics.identify me.id, traits analytics.identify me.id, traits
@ -109,7 +109,7 @@ module.exports = class Tracker extends CocoClass
mixpanelIncludes = ['', 'courses', 'courses/purchase', 'courses/teachers', 'courses/students', 'schools', 'teachers', 'teachers/freetrial', 'teachers/quote', 'play', 'play/level/dungeons-of-kithgard'] mixpanelIncludes = ['', 'courses', 'courses/purchase', 'courses/teachers', 'courses/students', 'schools', 'teachers', 'teachers/freetrial', 'teachers/quote', 'play', 'play/level/dungeons-of-kithgard']
mixpanel.track('page viewed', 'page name' : name, url : url) if name in mixpanelIncludes mixpanel.track('page viewed', 'page name' : name, url : url) if name in mixpanelIncludes
if @isTeacher() and @segmentLoaded if me.isTeacher() and @segmentLoaded
options = {} options = {}
if includeIntegrations?.length if includeIntegrations?.length
options.integrations = All: false options.integrations = All: false
@ -140,7 +140,7 @@ module.exports = class Tracker extends CocoClass
# Only log explicit events for now # Only log explicit events for now
mixpanel.track(action, properties) if 'Mixpanel' in includeIntegrations mixpanel.track(action, properties) if 'Mixpanel' in includeIntegrations
if @isTeacher() and @segmentLoaded if me.isTeacher() and @segmentLoaded
options = {} options = {}
if includeIntegrations if includeIntegrations
# https://segment.com/docs/libraries/analytics.js/#selecting-integrations # https://segment.com/docs/libraries/analytics.js/#selecting-integrations
@ -186,11 +186,8 @@ module.exports = class Tracker extends CocoClass
return unless me and @isProduction and not me.isAdmin() return unless me and @isProduction and not me.isAdmin()
ga? 'send', 'timing', category, variable, duration, label ga? 'send', 'timing', category, variable, duration, label
isTeacher: ->
return me.get('role') in ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent']
updateRole: -> updateRole: ->
return unless @isTeacher() return unless me.isTeacher()
return require('core/services/segment')() unless @segmentLoaded return require('core/services/segment')() unless @segmentLoaded
@identify() @identify()
#analytics.page() # It looks like we don't want to call this here because it somehow already gets called once in addition to this. #analytics.page() # It looks like we don't want to call this here because it somehow already gets called once in addition to this.

View file

@ -25,8 +25,9 @@
im_a_student: "I'm a Student" im_a_student: "I'm a Student"
learn_more: "Learn more" learn_more: "Learn more"
classroom_in_a_box: "A classroom in-a-box for teaching computer science." classroom_in_a_box: "A classroom in-a-box for teaching computer science."
codecombat_is: "CodeCombat is a platform for students to learn computer science while playing through a real game." codecombat_is: "CodeCombat is a platform <strong>for students</strong> to learn computer science while playing through a real game." # {change}
our_courses: "Our courses have been specifically playtested to excel in a classroom setting, even by teachers with little to no prior programming experience." our_courses: "Our courses have been specifically playtested to <strong>excel in the classroom</strong>, even by teachers with little to no prior programming experience." # {change}
top_screenshots_hint: "Students write code and see their changes update in real-time"
designed_with: "Designed with teachers in mind" designed_with: "Designed with teachers in mind"
real_code: "Real, typed code" real_code: "Real, typed code"
from_the_first_level: "from the first level" from_the_first_level: "from the first level"
@ -57,9 +58,15 @@
great_game: "A great game is more than just badges and achievements - its about a players journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence." great_game: "A great game is more than just badges and achievements - its about a players journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence."
agency: "CodeCombat is a game that gives players that agency and confidence with our robust typed code engine, which helps beginner and advanced students alike write proper, valid code." agency: "CodeCombat is a game that gives players that agency and confidence with our robust typed code engine, which helps beginner and advanced students alike write proper, valid code."
curious: "Curious? Request a demo and we'll show you the ropes" curious: "Curious? Request a demo and we'll show you the ropes"
request_demo_title: "Get your students started today!"
request_demo_subtitle: "Request a demo and get your students started in less than an hour."
get_started_title: "Set up your class today"
get_started_subtitle: "Set up a class, add your students, and monitor their progress as they learn computer science."
create_class: "Or create a class and see it for yourself!" create_class: "Or create a class and see it for yourself!"
teacher_screenshots_hint: "Students write code and see their changes update in real-time"
request_demo: "Request a Demo" request_demo: "Request a Demo"
create_a_class: "Create a Class" create_a_class: "Create a Class"
setup_a_class: "Set Up a Class"
have_an_account: "Already have an account?" have_an_account: "Already have an account?"
logged_in_as: "You are currently logged in as" logged_in_as: "You are currently logged in as"
view_my_classes: "View my classes" view_my_classes: "View my classes"
@ -702,9 +709,9 @@
more_info_3: "is a good place to connect with fellow educators who are using CodeCombat." more_info_3: "is a good place to connect with fellow educators who are using CodeCombat."
teachers_quote: teachers_quote:
name: "Quote Form" name: "Demo Form" # {change}
title: "Request a Quote" title: "Request a Demo" # {change}
subtitle: "Get CodeCombat in your classroom, club, school or district!" subtitle: "Get your students started in less than an hour. You'll be able to <strong>create a class, add students, and monitor their progress</strong> as they learn computer science." # {change}
email_exists: "User exists with this email." email_exists: "User exists with this email."
phone_number: "Phone number" phone_number: "Phone number"
phone_number_help: "Where can we reach you during the workday?" phone_number_help: "Where can we reach you during the workday?"
@ -728,10 +735,10 @@
middle_school: "Middle School" middle_school: "Middle School"
college_plus: "College or higher" college_plus: "College or higher"
anything_else: "Anything else we should know?" anything_else: "Anything else we should know?"
thanks_header: "Thanks for requesting a quote!" thanks_header: "Thanks for requesting a demo!" # {change}
thanks_p: "We'll be in touch soon. Questions? Email us:" thanks_p: "We'll be in touch soon. Questions? Email us:"
thanks_anon: "Login or sign up with your account below to access your two free enrollments (well notify you by email when they have been approved, which usually takes less than 48 hours). As always, the first hour of content is free for an unlimited number of students." thanks_anon: "Log in or create an account to set up a class, add your students, and monitor their progress as they learn computer science." # {change}
thanks_logged_in: "Your two free enrollments are pending approval. Well notify you by email when they have been approved (usually within 48 hours). As always, the first hour of content is free for an unlimited number of students." thanks_logged_in: "Set up a class, add your students, and monitor their progress as they learn computer science." # {change}
versions: versions:
save_version_title: "Save New Version" save_version_title: "Save New Version"

View file

@ -59,6 +59,9 @@ module.exports = class User extends CocoModel
isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled
isTeacher: ->
return @get('role') in ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent']
setRole: (role, force=false) -> setRole: (role, force=false) ->
return if me.isAdmin() return if me.isAdmin()
oldRole = @get 'role' oldRole = @get 'role'

View file

@ -72,7 +72,41 @@
#classroom-in-box-row #classroom-in-box-row
margin: 40px 0 margin: 40px 0
.top-screenshots
margin-bottom: 100px
margin-top: 50px
.label
color: black
display: block
.screenshots
text-align: center
.screenshot-grid
img
display: inline-block
margin: 6.5px
width: 800px
border-radius: 8px
.teacher-screenshots
padding: 10px
.label
color: black
display: block
.screenshots
text-align: center
.screenshot-grid
img
display: inline-block
margin: 6.5px
width: 300px
border-radius: 4px
#screenshot-lightbox
.modal-dialog
width: auto
max-width: 1024px
#feature-spread-row #feature-spread-row
.col-sm-4 .col-sm-4
padding: 40px padding: 40px
@ -177,6 +211,9 @@
left: 100% left: 100%
top: 0 top: 0
.have-an-account
font-size: 10pt
#school-level-label #school-level-label
margin: 15px 15px 0 0 margin: 15px 15px 0 0
display: inline-block display: inline-block

View file

@ -44,8 +44,18 @@ block content
.col-sm-6 .col-sm-6
h2.text-navy(data-i18n="new_home.classroom_in_a_box") h2.text-navy(data-i18n="new_home.classroom_in_a_box")
.col-sm-6 .col-sm-6
p(data-i18n="new_home.codecombat_is") p(data-i18n="[html]new_home.codecombat_is")
p(data-i18n="new_home.our_courses") p(data-i18n="[html]new_home.our_courses")
.top-screenshots
.screenshots
.hidden-sm.hidden-md.hidden-lg
small(data-i18n="new_home.top_screenshots_hint")
.screenshot-grid(title='Click to view full size')
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='0')
img(src="/images/pages/home/desert.png")
.clearfix.hidden-xs
small(data-i18n="new_home.top_screenshots_hint")
#feature-spread-row.row.text-center #feature-spread-row.row.text-center
h3(data-i18n="new_home.designed_with") h3(data-i18n="new_home.designed_with")
@ -148,24 +158,37 @@ block content
p p
span(data-i18n="new_home.agency") span(data-i18n="new_home.agency")
.request-demo-row.text-center .request-demo-row.text-center
h3(data-i18n="new_home.curious") if me.isTeacher()
h4(data-i18n="new_home.create_class") h3(data-i18n="new_home.get_started_title")
div else
a.btn.btn-primary.btn-lg(href="/teachers/freetrial", data-i18n="new_home.request_demo") h3(data-i18n="new_home.request_demo_title")
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers", data-i18n="new_home.create_a_class")
div .teacher-screenshots
if me.isAnonymous() .screenshots
.hidden-sm.hidden-md.hidden-lg
small(data-i18n="new_home.teacher_screenshots_hint")
.screenshot-grid(title='Click to view full size')
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='1')
img(src="/images/pages/about/forest.png")
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='2')
img(src="/images/pages/about/dungeon.png")
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='3')
img(src="/images/pages/about/glacier.png")
.clearfix.hidden-xs
small(data-i18n="new_home.teacher_screenshots_hint")
if me.isTeacher()
h4(data-i18n="new_home.get_started_subtitle")
div
a.btn.btn-primary.btn-lg(href="/courses/teachers", data-i18n="new_home.setup_a_class")
else
h4(data-i18n="new_home.request_demo_subtitle")
div
a.btn.btn-primary.btn-lg(href="/teachers/demo", data-i18n="new_home.request_demo")
.have-an-account
span.spr(data-i18n="new_home.have_an_account") span.spr(data-i18n="new_home.have_an_account")
a.login-button Login a.login-button Login
else
span.spr(data-i18n="new_home.logged_in_as")
span= me.broadName()
span.spr .
a(href="/courses/teachers", data-i18n="new_home.view_my_classes")
span.spr.spl(data-i18n="general.or")
a#logout-button logout
h3.text-center(data-i18n="new_home.computer_science") h3.text-center(data-i18n="new_home.computer_science")
h4.text-center h4.text-center
@ -246,9 +269,41 @@ block content
h6 PC Mag h6 PC Mag
.small pcmag.com .small pcmag.com
.request-demo-row.text-center .request-demo-row.text-center
h3(data-i18n="new_home.run_class") h3(data-i18n="new_home.run_class")
p if me.isTeacher()
a.btn.btn-primary.btn-lg(href="/teachers/freetrial", data-i18n="new_home.request_demo") div
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers", data-i18n="new_home.create_a_class") a.btn.btn-primary.btn-lg(href="/courses/teachers", data-i18n="new_home.setup_a_class")
else
div
a.btn.btn-primary.btn-lg(href="/teachers/demo", data-i18n="new_home.request_demo")
.have-an-account
span.spr(data-i18n="new_home.have_an_account")
a.login-button Login
#screenshot-lightbox.modal.fade(data-show="false")
.modal-dialog
.modal-content
#screenshot-carousel.carousel
ol.carousel-indicators
li(data-target=".screenshot-display", data-slide-to="0").active
li(data-target=".screenshot-display", data-slide-to="1")
li(data-target=".screenshot-display", data-slide-to="2")
li(data-target=".screenshot-display", data-slide-to="3")
.carousel-inner
.item.active
img#screenshot-desert(src="/images/pages/home/desert.png")
.item
img#screenshot-forest(src="/images/pages/about/forest.png")
.item
img#screenshot-dungeon(src="/images/pages/about/dungeon.png")
.item
img#screenshot-glacier(src="/images/pages/about/glacier.png")
a#carousel-left.left.carousel-control(href="#screenshot-carousel", role="button")
span.glyphicon.glyphicons-chevron-left.glyphicon-chevron-left(aria-hidden="true")
span.sr-only(data-i18n="about.previous")
a#carousel-right.right.carousel-control(href="#screenshot-carousel", role="button")
span.glyphicon.glyphicons-chevron-right.glyphicon-chevron-right(aria-hidden="true")
span.sr-only(data-i18n="about.next")

View file

@ -4,7 +4,7 @@ block content
.container .container
form.form(class=view.trialRequest.isNew() ? '' : 'hide') form.form(class=view.trialRequest.isNew() ? '' : 'hide')
h3.text-center(data-i18n="teachers_quote.title") h3.text-center(data-i18n="teachers_quote.title")
h4.text-center(data-i18n="teachers_quote.subtitle") h4.text-center(data-i18n="[html]teachers_quote.subtitle")
#form-teacher-info.section #form-teacher-info.section
.row .row
@ -133,7 +133,7 @@ block content
textarea.form-control(rows=8, name="notes") textarea.form-control(rows=8, name="notes")
#buttons-row.row.text-center #buttons-row.row.text-center
input#submit-request-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]common.send") input#submit-request-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]teachers_quote.title")
#form-submit-success.text-center(class=view.trialRequest.isNew() ? 'hide' : '') #form-submit-success.text-center(class=view.trialRequest.isNew() ? 'hide' : '')
@ -149,4 +149,6 @@ block content
button#login-btn.btn.btn-info(data-i18n="login.log_in") button#login-btn.btn.btn-info(data-i18n="login.log_in")
button#signup-btn.btn.btn-info(data-i18n="login.sign_up") button#signup-btn.btn.btn-info(data-i18n="login.sign_up")
else else
p.text-center(data-i18n="teachers_quote.thanks_logged_in") p.text-center(data-i18n="teachers_quote.thanks_logged_in")
div
a.btn.btn-primary.btn-lg(href="/courses/teachers", data-i18n="teachers_quote.setup_a_class")

View file

@ -16,6 +16,14 @@ module.exports = class NewHomeView extends RootView
'change #school-level-dropdown': 'onChangeSchoolLevelDropdown' 'change #school-level-dropdown': 'onChangeSchoolLevelDropdown'
'click #teacher-btn': 'onClickTeacherButton' 'click #teacher-btn': 'onClickTeacherButton'
'click #learn-more-link': 'onClickLearnMoreLink' 'click #learn-more-link': 'onClickLearnMoreLink'
'click .screen-thumbnail': 'onClickScreenThumbnail'
'click #carousel-left': 'onLeftPressed'
'click #carousel-right': 'onRightPressed'
shortcuts:
'right': 'onRightPressed'
'left': 'onLeftPressed'
'esc': 'onEscapePressed'
initialize: (options) -> initialize: (options) ->
@jumbotron = options.jumbotron or utils.getQueryVariable('jumbotron') or 'student' @jumbotron = options.jumbotron or utils.getQueryVariable('jumbotron') or 'student'
@ -47,6 +55,11 @@ module.exports = class NewHomeView extends RootView
afterRender: -> afterRender: ->
@onChangeSchoolLevelDropdown() @onChangeSchoolLevelDropdown()
@$('#screenshot-lightbox').modal()
@$('#screenshot-carousel').carousel({
interval: 0
keyboard: false
})
super() super()
onChangeSchoolLevelDropdown: (e) -> onChangeSchoolLevelDropdown: (e) ->
@ -75,5 +88,26 @@ module.exports = class NewHomeView extends RootView
onClickTeacherButton: -> onClickTeacherButton: ->
@scrollToLink('.request-demo-row', 600) @scrollToLink('.request-demo-row', 600)
onRightPressed: (event) ->
# Special handling, otherwise after you click the control, keyboard presses move the slide twice
return if event.type is 'keydown' and $(document.activeElement).is('.carousel-control')
if $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
$('#screenshot-carousel').carousel('next')
onLeftPressed: (event) ->
return if event.type is 'keydown' and $(document.activeElement).is('.carousel-control')
if $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
$('#screenshot-carousel').carousel('prev')
onEscapePressed: (event) ->
if $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
$('#screenshot-lightbox').modal('hide')
onClickScreenThumbnail: (event) ->
unless $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
# Modal opening happens automatically from bootstrap
$('#screenshot-carousel').carousel($(event.currentTarget).data("index"))

View file

@ -24,3 +24,4 @@ module.exports.templates =
course_invite_email: 'tem_u6D2EFWYC5Ptk38bSykjsU' course_invite_email: 'tem_u6D2EFWYC5Ptk38bSykjsU'
teacher_free_trial: 'tem_R7d9Hpoba9SceQNiYSXBak' teacher_free_trial: 'tem_R7d9Hpoba9SceQNiYSXBak'
teacher_free_trial_hoc: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc' teacher_free_trial_hoc: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc'
teacher_request_demo: 'tem_cwG3HZjEyb6QE493hZuUra'

View file

@ -6,6 +6,7 @@ hipchat = require '../hipchat'
sendwithus = require '../sendwithus' sendwithus = require '../sendwithus'
Prepaid = require '../prepaids/Prepaid' Prepaid = require '../prepaids/Prepaid'
jsonSchema = require '../../app/schemas/models/trial_request.schema' jsonSchema = require '../../app/schemas/models/trial_request.schema'
Classroom = require '../classrooms/Classroom'
User = require '../users/User' User = require '../users/User'
TrialRequestSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref} TrialRequestSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref}
@ -41,9 +42,21 @@ TrialRequestSchema.post 'save', (doc) ->
emailParams = emailParams =
recipient: recipient:
address: email address: email
email_id: sendwithus.templates.teacher_free_trial email_id: sendwithus.templates.teacher_request_demo
sendwithus.api.send emailParams, (err, result) => email_data:
log.error "sendwithus trial request approved error: #{err}, result: #{result}" if err account_exists: user?.get('anonymous') is false
classes_exist: false
if user?.get('anonymous') is false
Classroom.findOne {ownerID: user.get('_id')}, (err, classroom) =>
if err
log.error "Trial request classroom find error: #{err}"
return
emailParams.email_data.classes_exist = classroom?
sendwithus.api.send emailParams, (err, result) =>
log.error "sendwithus trial request approved error: #{err}, result: #{result}" if err
else
sendwithus.api.send emailParams, (err, result) =>
log.error "sendwithus trial request approved error: #{err}, result: #{result}" if err
closeIO.createSalesLead(user, email, closeIO.createSalesLead(user, email,
name: trialProperties.name name: trialProperties.name