mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-26 05:53:39 -04:00
Add completion stats to /courses
This commit is contained in:
parent
07ad8382cc
commit
405785bafe
4 changed files with 64 additions and 25 deletions
app
models
styles/courses
templates/courses
views/courses
|
@ -11,5 +11,26 @@ module.exports = class Campaign extends CocoModel
|
|||
@denormalizedLevelProperties: _.keys(_.omit(schema.properties.levels.additionalProperties.properties, ['unlocks', 'position', 'rewards']))
|
||||
@denormalizedCampaignProperties: ['name', 'i18n', 'slug']
|
||||
|
||||
levelsCollection: ->
|
||||
new CocoCollection(_.values(@get('levels')), {model: Level})
|
||||
statsForSessions: (sessions) ->
|
||||
# common code for crunching stats for a user's progress on a campaign/course
|
||||
stats = {}
|
||||
sessions = _.sortBy sessions.models, (s) -> s.get('changed')
|
||||
levels = _.values(@get('levels'))
|
||||
levels = (level for level in levels when not _.contains(level.type, 'ladder'))
|
||||
levelOriginals = _.pluck(levels, 'original')
|
||||
sessionOriginals = (session.get('level').original for session in sessions when session.get('state').complete)
|
||||
levelsLeft = _.size(_.difference(levelOriginals, sessionOriginals))
|
||||
lastSession = _.last(sessions)
|
||||
stats.levels = {
|
||||
size: _.size(levels)
|
||||
left: levelsLeft
|
||||
done: levelsLeft is 0
|
||||
numDone: _.size(levels) - levelsLeft
|
||||
pctDone: (100 * (_.size(levels) - levelsLeft) / _.size(levels)).toFixed(1) + '%'
|
||||
lastPlayed: if lastSession then _.findWhere levels, { original: lastSession.get('level').original } else null
|
||||
first: _.first(levels)
|
||||
arena: _.find _.values(@get('levels')), (level) -> _.contains(level.type, 'ladder')
|
||||
}
|
||||
sum = (nums) -> _.reduce(nums, (s, num) -> s + num)
|
||||
stats.playtime = sum((session.get('playtime') or 0 for session in sessions))
|
||||
return stats
|
|
@ -29,3 +29,11 @@
|
|||
|
||||
.course-instance-entry
|
||||
padding-left: 40px
|
||||
|
||||
.progress-bar
|
||||
min-width: 15%
|
||||
|
||||
.btn
|
||||
margin-left: 20px
|
||||
min-width: 180px
|
||||
|
|
@ -28,8 +28,11 @@ block content
|
|||
else
|
||||
|
||||
- var showHOCComplete = false;
|
||||
if false && view.hocCourseInstance
|
||||
- showHOCComplete = view.hocCourseInstance.sessions.allDone();
|
||||
if view.hocCourseInstance
|
||||
- var course = view.courses.get(view.hocCourseInstance.get('courseID'));
|
||||
- var campaign = view.campaigns.get(course.get('campaignID'));
|
||||
- var stats = campaign.statsForSessions(view.hocCourseInstance.sessions);
|
||||
- showHOCComplete = stats.levels.done;
|
||||
|
||||
.text-center
|
||||
if !showHOCComplete
|
||||
|
@ -43,7 +46,7 @@ block content
|
|||
li Learn even more programming!
|
||||
a.btn.btn-lg.btn-success(href="/play")
|
||||
|
||||
if false && view.hocCourseInstance
|
||||
if view.hocCourseInstance && !view.classrooms.size()
|
||||
h3 Saved Games
|
||||
hr
|
||||
|
||||
|
@ -56,7 +59,7 @@ block content
|
|||
+course-instance-body(view.hocCourseInstance)
|
||||
.clearfix
|
||||
|
||||
if view.classrooms.size()
|
||||
else if view.classrooms.size()
|
||||
h3.text-uppercase My Classes
|
||||
hr
|
||||
|
||||
|
@ -111,29 +114,43 @@ block content
|
|||
mixin course-instance-body(courseInstance)
|
||||
- var course = view.courses.get(courseInstance.get('courseID'));
|
||||
- var campaign = view.campaigns.get(course.get('campaignID'));
|
||||
- var levels = campaign.levelsCollection();
|
||||
- var complete = view.isCampaignComplete(campaign, courseInstance.sessions);
|
||||
if complete
|
||||
- var stats = campaign.statsForSessions(courseInstance.sessions);
|
||||
if stats.levels.done
|
||||
.text-success
|
||||
span.glyphicon.glyphicon-ok
|
||||
span.spl Course Complete!
|
||||
.pull-right
|
||||
if complete
|
||||
- var arenaLevel = levels.findWhere({ type: 'course-ladder' });
|
||||
if stats.levels.done
|
||||
- var arenaLevel = stats.levels.arena;
|
||||
if arenaLevel
|
||||
- var arenaURL = "/play/ladder/"+arenaLevel.get('slug')+"/course/"+courseInstance.id;
|
||||
- var arenaURL = "/play/ladder/"+arenaLevel.slug+"/course/"+courseInstance.id;
|
||||
a.btn.btn-warning.btn-lg(href=arenaURL)
|
||||
| Play Arena
|
||||
else
|
||||
a.btn.btn-default.btn-lg(disabled=true) Course Complete
|
||||
else if courseInstance.sessions.size()
|
||||
- var lastSession = courseInstance.sessions.last();
|
||||
- var lastLevel = levels.findWhere({original: lastSession.get('level').original});
|
||||
- var levelURL = "/play/level/"+lastLevel.get('slug')+"?course="+courseInstance.get('courseID')+"&course-instance="+courseInstance.id;
|
||||
- var lastLevel = stats.levels.lastPlayed;
|
||||
- var levelURL = "/play/level/"+lastLevel.slug+"?course="+courseInstance.get('courseID')+"&course-instance="+courseInstance.id;
|
||||
a.btn.btn-success.btn-lg(href=levelURL)
|
||||
| Continue
|
||||
else
|
||||
- var firstLevel = levels.first();
|
||||
- var levelURL = "/play/level/"+firstLevel.get('slug')+"?course="+courseInstance.get('courseID')+"&course-instance="+courseInstance.id;
|
||||
- var firstLevel = stats.levels.first;
|
||||
- var levelURL = "/play/level/"+firstLevel.slug+"?course="+courseInstance.get('courseID')+"&course-instance="+courseInstance.id;
|
||||
a.btn.btn-info.btn-lg(href=levelURL)
|
||||
| Start
|
||||
|
||||
div
|
||||
span Playtime
|
||||
span.spr :
|
||||
span= moment.duration(stats.playtime, 'seconds').humanize()
|
||||
|
||||
if stats.levels.lastPlayed
|
||||
div
|
||||
span Last Level
|
||||
span.spr :
|
||||
span= stats.levels.lastPlayed.name
|
||||
|
||||
.progress
|
||||
.progress-bar(style="width:"+stats.levels.pctDone)= stats.levels.pctDone
|
||||
|
||||
|
|
@ -49,19 +49,12 @@ module.exports = class CoursesView extends RootView
|
|||
model: LevelSession
|
||||
})
|
||||
courseInstance.sessions.comparator = 'changed'
|
||||
@supermodel.loadCollection(courseInstance.sessions, 'sessions', { data: { project: 'state.complete level.original' }})
|
||||
@supermodel.loadCollection(courseInstance.sessions, 'sessions', { data: { project: 'state.complete level.original playtime changed' }})
|
||||
|
||||
@hocCourseInstance = @courseInstances.findWhere({hourOfCode: true})
|
||||
if @hocCourseInstance
|
||||
@courseInstances.remove(@hocCourseInstance)
|
||||
|
||||
isCampaignComplete: (campaign, sessions) ->
|
||||
levels = _.values(campaign.get('levels'))
|
||||
levels = (level for level in levels when not _.contains(level.type, 'ladder'))
|
||||
levelOriginals = _.pluck(levels, 'original')
|
||||
sessionOriginals = (session.get('level').original for session in sessions.models)
|
||||
return _.size(_.difference(levelOriginals, sessionOriginals)) is 0
|
||||
|
||||
onClickStartNewGameButton: ->
|
||||
@openSignUpModal()
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue