mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-30 14:51:13 -04:00
Update Hour of Code student flow and tracking, remove signup requirement
This commit is contained in:
parent
c969768800
commit
d776809e1c
8 changed files with 49 additions and 15 deletions
app
templates
views
server/courses
|
@ -38,7 +38,7 @@ block content
|
|||
- i++
|
||||
|
||||
mixin hoc-landing
|
||||
h1.center Welcome Hour of Code!
|
||||
h1.center Welcome to CodeCombat's Hour of Code!
|
||||
br
|
||||
.container-fluid
|
||||
.row
|
||||
|
@ -53,7 +53,7 @@ mixin student-main
|
|||
|
||||
mixin teacher-hoc
|
||||
button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
|
||||
h1.center Welcome Hour of Code!
|
||||
h1.center Welcome to CodeCombat's Hour of Code!
|
||||
p
|
||||
strong How to use CodeCombat with your students:
|
||||
ol
|
||||
|
|
|
@ -36,11 +36,11 @@ block outer_content
|
|||
|
||||
|
||||
block extra_footer_content
|
||||
if explainHourOfCode
|
||||
if explainsHourOfCode
|
||||
// Does not show up unless lang is en-US.
|
||||
div.hour-of-code-explanation
|
||||
| The 'Hour of Code' is a nationwide initiative by
|
||||
a(href="http://csedweek.org") Computer Science Education Week
|
||||
| and
|
||||
a(href="http://code.org") Code.org
|
||||
| to introduce millions of students to one hour of computer science and computer programming.
|
||||
| to introduce millions of students to one hour of computer science and computer programming.
|
||||
|
|
|
@ -46,6 +46,8 @@ module.exports = class HomeView extends RootView
|
|||
@$el.addClass 'hour-of-code' if @explainsHourOfCode
|
||||
|
||||
setUpHourOfCode: ->
|
||||
# All this HoC stuff is for the 2014-2015 year. 2015-2016 year lands at /hoc instead (the courses view).
|
||||
# TODO: get rid of all this sometime in November 2015 when code.org/learn updates to the new version for Hour of Code tutorials.
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
if elapsed < 5 * 60 * 1000
|
||||
me.set 'hourOfCode', true
|
||||
|
|
|
@ -9,6 +9,8 @@ User = require 'models/User'
|
|||
utils = require 'core/utils'
|
||||
Prepaid = require 'models/Prepaid'
|
||||
|
||||
autoplayedOnce = false
|
||||
|
||||
module.exports = class CourseDetailsView extends RootView
|
||||
id: 'course-details-view'
|
||||
template: template
|
||||
|
@ -64,7 +66,7 @@ module.exports = class CourseDetailsView extends RootView
|
|||
|
||||
onCourseSync: ->
|
||||
# console.log 'onCourseSync'
|
||||
if me.isAnonymous()
|
||||
if me.isAnonymous() and not me.get('hourOfCode')
|
||||
@noCourseInstance = true
|
||||
@render?()
|
||||
return
|
||||
|
@ -117,7 +119,7 @@ module.exports = class CourseDetailsView extends RootView
|
|||
|
||||
onCourseInstanceSync: ->
|
||||
# console.log 'onCourseInstanceSync'
|
||||
@adminMode = true if @courseInstance.get('ownerID') is me.id
|
||||
@adminMode = true if @courseInstance.get('ownerID') is me.id and @courseInstance.get('name') isnt 'Single Player'
|
||||
@levelSessions = new CocoCollection([], { url: "/db/course_instance/#{@courseInstance.id}/level_sessions", model: LevelSession, comparator:'_id' })
|
||||
@listenToOnce @levelSessions, 'sync', @onLevelSessionsSync
|
||||
@supermodel.loadCollection @levelSessions, 'level_sessions', cache: false
|
||||
|
@ -180,6 +182,11 @@ module.exports = class CourseDetailsView extends RootView
|
|||
@conceptsCompleted[concept]++
|
||||
@render?()
|
||||
|
||||
# If we just joined a single-player course for Hour of Code, we automatically play.
|
||||
if @instanceStats.totalLevelsCompleted is 0 and @instanceStats.totalPlayTime is 0 and @courseInstance.get('members').length is 1 and me.get('hourOfCode') and not @adminMode and not autoplayedOnce
|
||||
autoplayedOnce = true
|
||||
@$el.find('button.btn-play-level').click()
|
||||
|
||||
onMembersSync: ->
|
||||
# console.log 'onMembersSync'
|
||||
@memberUserMap = {}
|
||||
|
|
|
@ -17,15 +17,14 @@ module.exports = class CoursesView extends RootView
|
|||
'click .btn-buy': 'onClickBuy'
|
||||
'click .btn-enroll': 'onClickEnroll'
|
||||
'click .btn-enter': 'onClickEnter'
|
||||
'click .btn-hoc-student-continue': 'onClickHocStudentContinue'
|
||||
'click .btn-hoc-student-continue': 'onClickHOCStudentContinue'
|
||||
'click .btn-student': 'onClickStudent'
|
||||
'click .btn-teacher': 'onClickTeacher'
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
@setUpHourOfCode()
|
||||
@praise = utils.getCoursePraise()
|
||||
@hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
|
||||
@hocMode = utils.getQueryVariable('hoc', false)
|
||||
@studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0
|
||||
@courses = new CocoCollection([], { url: "/db/course", model: Course})
|
||||
@supermodel.loadCollection(@courses, 'courses')
|
||||
|
@ -39,6 +38,21 @@ module.exports = class CoursesView extends RootView
|
|||
@studentMode = true
|
||||
@courseEnroll(prepaidCode)
|
||||
|
||||
setUpHourOfCode: ->
|
||||
# If we are coming in at /hoc, then we show the landing page.
|
||||
# If we have ?hoc=true (for the step after the landing page), then we show any HoC-specific instructions.
|
||||
# If we haven't tracked this player as an hourOfCode player yet, and it's a new account, we do that now.
|
||||
@hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
|
||||
@hocMode = utils.getQueryVariable('hoc', false)
|
||||
elapsed = new Date() - new Date(me.get('dateCreated'))
|
||||
if not me.get('hourOfCode') and (@hocLandingPage or @hocMode) and elapsed < 5 * 60 * 1000
|
||||
me.set('hourOfCode', true)
|
||||
me.patch()
|
||||
$('body').append($('<img src="https://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin'
|
||||
if me.get('hourOfCode') and elapsed < 24 * 60 * 60 * 1000
|
||||
@hocMode = true # If they really just arrived, make sure we're still in hocMode even if they lost ?hoc=true.
|
||||
|
||||
getRenderData: ->
|
||||
context = super()
|
||||
context.courses = @courses.models ? []
|
||||
|
@ -102,10 +116,12 @@ module.exports = class CoursesView extends RootView
|
|||
navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs
|
||||
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
||||
|
||||
onClickHocStudentContinue: (e) ->
|
||||
onClickHOCStudentContinue: (e) ->
|
||||
$('.continue-dialog').modal('hide')
|
||||
return @openModalView new AuthModal() if me.isAnonymous()
|
||||
courseID = $(e.target).data('course-id')
|
||||
if e
|
||||
courseID = $(e.target).data('course-id')
|
||||
else
|
||||
courseID = '560f1a9f22961295f9427742'
|
||||
|
||||
@state = 'enrolling'
|
||||
@stateMessage = undefined
|
||||
|
@ -117,6 +133,7 @@ module.exports = class CoursesView extends RootView
|
|||
name: 'Single Player'
|
||||
seats: 9999
|
||||
courseID: courseID
|
||||
hourOfCode: true
|
||||
jqxhr = $.post('/db/course_instance/-/create', data)
|
||||
jqxhr.done (data, textStatus, jqXHR) =>
|
||||
application.tracker?.trackEvent 'Finished HoC student course creation', {courseID: courseID}
|
||||
|
@ -145,6 +162,10 @@ module.exports = class CoursesView extends RootView
|
|||
@render?()
|
||||
|
||||
onClickStudent: (e) ->
|
||||
if @supermodel.finished() and @hocLandingPage
|
||||
# Automatically enroll in first course
|
||||
@onClickHOCStudentContinue()
|
||||
return
|
||||
route = "/courses/students"
|
||||
route += "?hoc=true" if @hocLandingPage or @hocMode
|
||||
viewClass = require 'views/courses/CoursesView'
|
||||
|
|
|
@ -106,6 +106,7 @@ module.exports = class CampaignView extends RootView
|
|||
window.tracker?.trackEvent 'Loaded World Map', category: 'World Map', label: @terrain
|
||||
|
||||
# If it's a new player who didn't appear to come from Hour of Code, we register her here without setting the hourOfCode property.
|
||||
# TODO: get rid of all this sometime in November 2015 when code.org/learn updates to the new version for Hour of Code tutorials.
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
if not trackedHourOfCode and not me.get('hourOfCode') and elapsed < 5 * 60 * 1000
|
||||
$('body').append($('<img src="https://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
|
||||
|
|
|
@ -189,11 +189,13 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
isHourOfCode = me.get('hourOfCode') or elapsed < 120 * 60 * 1000
|
||||
# Later we should only check me.get('hourOfCode'), but for now so much traffic comes in that we just assume it.
|
||||
# TODO: get rid of said assumption sometime in November 2015 when code.org/learn updates to the new version for Hour of Code tutorials.
|
||||
if isHourOfCode
|
||||
# Show the Hour of Code "I'm Done" tracking pixel after they played for 20 minutes
|
||||
enough = elapsed >= 20 * 60 * 1000
|
||||
lastLevel = @level.get('slug') is 'course-kithgard-gates'
|
||||
enough = elapsed >= 20 * 60 * 1000 or lastLevel
|
||||
tooMuch = elapsed > 120 * 60 * 1000
|
||||
showDone = elapsed >= 30 * 60 * 1000 and not tooMuch
|
||||
showDone = (elapsed >= 30 * 60 * 1000 and not tooMuch) or lastLevel
|
||||
if enough and not tooMuch and not me.get('hourOfCodeComplete')
|
||||
$('body').append($('<img src="http://code.org/api/hour/finish_codecombat.png" style="visibility: hidden;">'))
|
||||
me.set 'hourOfCodeComplete', true # Note that this will track even for players who don't have hourOfCode set.
|
||||
|
|
|
@ -38,7 +38,8 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
super arguments...
|
||||
|
||||
createAPI: (req, res) ->
|
||||
return @sendUnauthorizedError(res) if not req.user? or req.user?.isAnonymous()
|
||||
return @sendUnauthorizedError(res) if not req.user?
|
||||
return @sendUnauthorizedError(res) if req.user.isAnonymous() and not (req.body.hourOfCode and req.body.courseID is '560f1a9f22961295f9427742')
|
||||
|
||||
# Required Input
|
||||
seats = req.body.seats
|
||||
|
|
Loading…
Add table
Reference in a new issue