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/freetrial': go('RequestQuoteView')
'teachers/quote': go('RequestQuoteView')
'teachers/demo': go('RequestQuoteView')
'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']
traits[userTrait] ?= me.get(userTrait)
if @isTeacher()
if me.isTeacher()
traits.teacher = true
console.log 'Would identify', me.id, traits if debugAnalytics
@ -90,7 +90,7 @@ module.exports = class Tracker extends CocoClass
mixpanel.identify(me.id)
mixpanel.register(traits)
if @isTeacher() and @segmentLoaded
if me.isTeacher() and @segmentLoaded
traits.createdAt = me.get 'dateCreated' # Intercom, at least, wants this
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']
mixpanel.track('page viewed', 'page name' : name, url : url) if name in mixpanelIncludes
if @isTeacher() and @segmentLoaded
if me.isTeacher() and @segmentLoaded
options = {}
if includeIntegrations?.length
options.integrations = All: false
@ -140,7 +140,7 @@ module.exports = class Tracker extends CocoClass
# Only log explicit events for now
mixpanel.track(action, properties) if 'Mixpanel' in includeIntegrations
if @isTeacher() and @segmentLoaded
if me.isTeacher() and @segmentLoaded
options = {}
if includeIntegrations
# 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()
ga? 'send', 'timing', category, variable, duration, label
isTeacher: ->
return me.get('role') in ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent']
updateRole: ->
return unless @isTeacher()
return unless me.isTeacher()
return require('core/services/segment')() unless @segmentLoaded
@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.

View file

@ -25,8 +25,9 @@
im_a_student: "I'm a Student"
learn_more: "Learn more"
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."
our_courses: "Our courses have been specifically playtested to excel in a classroom setting, even by teachers with little to no prior programming experience."
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 <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"
real_code: "Real, typed code"
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."
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"
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!"
teacher_screenshots_hint: "Students write code and see their changes update in real-time"
request_demo: "Request a Demo"
create_a_class: "Create a Class"
setup_a_class: "Set Up a Class"
have_an_account: "Already have an account?"
logged_in_as: "You are currently logged in as"
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."
teachers_quote:
name: "Quote Form"
title: "Request a Quote"
subtitle: "Get CodeCombat in your classroom, club, school or district!"
name: "Demo Form" # {change}
title: "Request a Demo" # {change}
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."
phone_number: "Phone number"
phone_number_help: "Where can we reach you during the workday?"
@ -728,10 +735,10 @@
middle_school: "Middle School"
college_plus: "College or higher"
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_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_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_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: "Set up a class, add your students, and monitor their progress as they learn computer science." # {change}
versions:
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
isTeacher: ->
return @get('role') in ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent']
setRole: (role, force=false) ->
return if me.isAdmin()
oldRole = @get 'role'

View file

@ -72,7 +72,41 @@
#classroom-in-box-row
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
.col-sm-4
padding: 40px
@ -177,6 +211,9 @@
left: 100%
top: 0
.have-an-account
font-size: 10pt
#school-level-label
margin: 15px 15px 0 0
display: inline-block

View file

@ -44,8 +44,18 @@ block content
.col-sm-6
h2.text-navy(data-i18n="new_home.classroom_in_a_box")
.col-sm-6
p(data-i18n="new_home.codecombat_is")
p(data-i18n="new_home.our_courses")
p(data-i18n="[html]new_home.codecombat_is")
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
h3(data-i18n="new_home.designed_with")
@ -148,24 +158,37 @@ block content
p
span(data-i18n="new_home.agency")
.request-demo-row.text-center
h3(data-i18n="new_home.curious")
h4(data-i18n="new_home.create_class")
div
a.btn.btn-primary.btn-lg(href="/teachers/freetrial", data-i18n="new_home.request_demo")
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers", data-i18n="new_home.create_a_class")
div
if me.isAnonymous()
if me.isTeacher()
h3(data-i18n="new_home.get_started_title")
else
h3(data-i18n="new_home.request_demo_title")
.teacher-screenshots
.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")
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")
h4.text-center
@ -246,9 +269,41 @@ block content
h6 PC Mag
.small pcmag.com
.request-demo-row.text-center
h3(data-i18n="new_home.run_class")
p
a.btn.btn-primary.btn-lg(href="/teachers/freetrial", data-i18n="new_home.request_demo")
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers", data-i18n="new_home.create_a_class")
if me.isTeacher()
div
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
form.form(class=view.trialRequest.isNew() ? '' : 'hide')
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
.row
@ -133,7 +133,7 @@ block content
textarea.form-control(rows=8, name="notes")
#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' : '')
@ -149,4 +149,6 @@ block content
button#login-btn.btn.btn-info(data-i18n="login.log_in")
button#signup-btn.btn.btn-info(data-i18n="login.sign_up")
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'
'click #teacher-btn': 'onClickTeacherButton'
'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) ->
@jumbotron = options.jumbotron or utils.getQueryVariable('jumbotron') or 'student'
@ -47,6 +55,11 @@ module.exports = class NewHomeView extends RootView
afterRender: ->
@onChangeSchoolLevelDropdown()
@$('#screenshot-lightbox').modal()
@$('#screenshot-carousel').carousel({
interval: 0
keyboard: false
})
super()
onChangeSchoolLevelDropdown: (e) ->
@ -75,5 +88,26 @@ module.exports = class NewHomeView extends RootView
onClickTeacherButton: ->
@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'
teacher_free_trial: 'tem_R7d9Hpoba9SceQNiYSXBak'
teacher_free_trial_hoc: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc'
teacher_request_demo: 'tem_cwG3HZjEyb6QE493hZuUra'

View file

@ -6,6 +6,7 @@ hipchat = require '../hipchat'
sendwithus = require '../sendwithus'
Prepaid = require '../prepaids/Prepaid'
jsonSchema = require '../../app/schemas/models/trial_request.schema'
Classroom = require '../classrooms/Classroom'
User = require '../users/User'
TrialRequestSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref}
@ -41,9 +42,21 @@ TrialRequestSchema.post 'save', (doc) ->
emailParams =
recipient:
address: email
email_id: sendwithus.templates.teacher_free_trial
sendwithus.api.send emailParams, (err, result) =>
log.error "sendwithus trial request approved error: #{err}, result: #{result}" if err
email_id: sendwithus.templates.teacher_request_demo
email_data:
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,
name: trialProperties.name