mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Worked in a lot of changes Scott proposed
This commit is contained in:
parent
06ba50f5e2
commit
9f0add22a5
26 changed files with 287 additions and 314 deletions
|
@ -4,6 +4,5 @@ EarnedAchievement = require 'models/EarnedAchievement'
|
|||
module.exports = class EarnedAchievementCollection extends CocoCollection
|
||||
model: EarnedAchievement
|
||||
|
||||
initialize: (me = require('lib/auth').me) ->
|
||||
@url = "/db/user/#{me.id}/achievements"
|
||||
|
||||
initialize: (userID) ->
|
||||
@url = "/db/user/#{userID}/achievements"
|
||||
|
|
|
@ -297,14 +297,12 @@ class CocoModel extends Backbone.Model
|
|||
|
||||
@pollAchievements: ->
|
||||
NewAchievementCollection = require '../collections/NewAchievementCollection' # Nasty mutual inclusion if put on top
|
||||
console.debug 'Polling for new achievements'
|
||||
achievements = new NewAchievementCollection
|
||||
achievements.fetch
|
||||
success: (collection) ->
|
||||
console.debug 'Polling for achievements success', collection
|
||||
me.fetch (success: -> Backbone.Mediator.publish('achievements:new', collection)) unless _.isEmpty(collection.models)
|
||||
error: (collection, res, options) ->
|
||||
console.error 'Miserably failed to fetch unnotified achievements'
|
||||
error: ->
|
||||
console.error 'Miserably failed to fetch unnotified achievements', arguments
|
||||
|
||||
CocoModel.pollAchievements = _.debounce CocoModel.pollAchievements, 500
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ module.exports = class LevelSession extends CocoModel
|
|||
false
|
||||
|
||||
isMultiplayer: ->
|
||||
console.log @get 'levelName'
|
||||
console.log @
|
||||
console.log @get 'team'
|
||||
@get('team')? # Only multiplayer level sessions have teams defined
|
||||
|
||||
completed: ->
|
||||
@get('state')?.complete || false
|
||||
|
|
|
@ -42,51 +42,13 @@ module.exports = class User extends CocoModel
|
|||
return "/file/#{photoURL}#{prefix}s=#{size}"
|
||||
return "/db/user/#{@id}/avatar?s=#{size}&employerPageAvatar=#{useEmployerPageAvatar}"
|
||||
|
||||
# Callbacks can be either 'success' or 'error'
|
||||
@getByID = (id, properties, force, callbacks={}) ->
|
||||
{me} = require 'lib/auth'
|
||||
if me.id is id
|
||||
callbacks.success me if callbacks.success?
|
||||
return me
|
||||
user = cache[id] or new module.exports({_id: id})
|
||||
if force or not cache[id]
|
||||
user.loading = true
|
||||
user.fetch(
|
||||
success: ->
|
||||
user.loading = false
|
||||
Backbone.Mediator.publish('user:fetched')
|
||||
callbacks.success arguments... if callbacks.success?
|
||||
error: -> callbacks.error arguments... if callbacks.error?
|
||||
)
|
||||
cache[id] = user
|
||||
user
|
||||
getSlugOrID: -> @get('slug') or @get('_id')
|
||||
|
||||
set: ->
|
||||
if arguments[0] is 'jobProfileApproved' and @get("jobProfileApproved") is false and not @get("jobProfileApprovedDate")
|
||||
@set "jobProfileApprovedDate", (new Date()).toISOString()
|
||||
super arguments...
|
||||
|
||||
# callbacks can be either success or error
|
||||
@getByIDOrSlug: (idOrSlug, force, callbacks={}) ->
|
||||
{me} = require 'lib/auth'
|
||||
isID = util.isID idOrSlug
|
||||
if me.id is idOrSlug or me.slug is idOrSlug
|
||||
callbacks.success me if callbacks.success?
|
||||
return me
|
||||
cached = cache[idOrSlug]
|
||||
user = cached or new @ _id: idOrSlug
|
||||
if force or not cached
|
||||
user.loading = true
|
||||
user.fetch
|
||||
success: ->
|
||||
user.loading = false
|
||||
Backbone.Mediator.publish 'user:fetched'
|
||||
callbacks.success user if callbacks.success?
|
||||
error: ->
|
||||
user.loading = false
|
||||
callbacks.error user if callbacks.error?
|
||||
cache[idOrSlug] = user
|
||||
user
|
||||
|
||||
@getUnconflictedName: (name, done) ->
|
||||
$.ajax "/auth/name/#{name}",
|
||||
success: (data) -> done data.name
|
||||
|
|
|
@ -35,7 +35,7 @@ MongoFindQuerySchema.definitions[MongoQueryOperatorSchema.id] = MongoQueryOperat
|
|||
|
||||
AchievementSchema = c.object()
|
||||
c.extendNamedProperties AchievementSchema
|
||||
c.extendBasicProperties AchievementSchema, 'achievement' # TODO What's this about?
|
||||
c.extendBasicProperties AchievementSchema, 'achievement'
|
||||
c.extendSearchableProperties AchievementSchema
|
||||
|
||||
_.extend AchievementSchema.properties,
|
||||
|
@ -51,8 +51,8 @@ _.extend AchievementSchema.properties,
|
|||
related: c.objectId(description: 'Related entity')
|
||||
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
||||
category:
|
||||
type: 'string'
|
||||
description: "E.g. 'level', 'ladder', 'contributor'..." # TODO might make this enum?
|
||||
enum: ['level', 'ladder', 'contributor']
|
||||
description: 'For categorizing and display purposes'
|
||||
difficulty: c.int
|
||||
description: 'The higher the more difficult'
|
||||
default: 1
|
||||
|
|
|
@ -21,8 +21,8 @@ PatchSchema = c.object({title: 'Patch', required: ['target', 'delta', 'commitMes
|
|||
minor: {type: 'number', minimum: 0}
|
||||
})
|
||||
|
||||
_wasPending: type: 'boolean'
|
||||
_newlyAccepted: type: 'boolean'
|
||||
wasPending: type: 'boolean'
|
||||
newlyAccepted: type: 'boolean'
|
||||
})
|
||||
|
||||
c.extendBasicProperties(PatchSchema, 'patch')
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
margin-bottom: 0px
|
||||
|
||||
img#picture
|
||||
max-width: 50%
|
||||
max-width: 100%
|
||||
|
||||
.panel
|
||||
margin-bottom: 10px
|
||||
|
@ -14,5 +14,19 @@
|
|||
h2
|
||||
margin-bottom: 0px
|
||||
|
||||
a
|
||||
font-size: 28px
|
||||
margin-left: 5px
|
||||
|
||||
.panel-title > a
|
||||
margin-left: 5px
|
||||
color: rgb(11, 99, 188)
|
||||
|
||||
.panel-me
|
||||
td
|
||||
padding-left: 15px
|
||||
|
||||
.panel-emails
|
||||
h4
|
||||
font-family: $font-family-base
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import 'bootstrap/variables'
|
||||
|
||||
.locked
|
||||
// This used to be a grayscale filter but they're mad intensive to paint
|
||||
|
||||
|
@ -22,7 +24,7 @@
|
|||
background-image: url("/images/achievements/achievement_background_locked.png")
|
||||
&:not(.locked)
|
||||
.achievement-content
|
||||
background-image: url("/images/achievements/achievement_background.png")
|
||||
background-image: url("/images/achievements/achievement_background_light.png")
|
||||
|
||||
.achievement-content
|
||||
background-size: 100% 100%
|
||||
|
@ -30,18 +32,23 @@
|
|||
overflow: hidden
|
||||
|
||||
> .achievement-title
|
||||
font-family: Bangers
|
||||
font-family: $font-family-base
|
||||
font-weight: bold
|
||||
white-space: nowrap
|
||||
max-height: 2em
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
|
||||
|
||||
> .achievement-description
|
||||
white-space: initial
|
||||
font-size: 12px
|
||||
line-height: 1.3em
|
||||
overflow: hidden
|
||||
max-height: 2.6em
|
||||
margin-top: auto
|
||||
margin-bottom: 0px !important
|
||||
padding-left: 5px
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
|
||||
// Specific to the user stats page
|
||||
|
@ -75,7 +82,6 @@
|
|||
|
||||
.achievement-title
|
||||
font-size: 20px
|
||||
padding-left: -50px
|
||||
|
||||
.achievement-description
|
||||
font-size: 12px
|
||||
|
@ -105,12 +111,14 @@
|
|||
bottom: 0
|
||||
|
||||
.achievement-content
|
||||
background-image: url("/images/achievements/achievement_background.png")
|
||||
position: relative
|
||||
width: 450px
|
||||
height: 160px
|
||||
padding: 24px 30px 20px 60px
|
||||
|
||||
.achievement-title
|
||||
font-family: Bangers
|
||||
font-size: 28px
|
||||
padding-left: -50px
|
||||
|
||||
|
@ -209,11 +217,14 @@
|
|||
.user-level
|
||||
z-index: 1000
|
||||
box-shadow: 0 0 0 1px black, 0 0 0 3px lightgrey, 0 0 0 4px black
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif
|
||||
font-family: $font-family-base
|
||||
|
||||
// Achievements page
|
||||
h2.achievements-category
|
||||
.achievement-category-title
|
||||
margin-left: 20px
|
||||
font-family: $font-family-base
|
||||
font-weight: bold
|
||||
color: #5a5a5a
|
||||
|
||||
.table-layout
|
||||
#no-achievements
|
||||
|
|
|
@ -1,172 +1,138 @@
|
|||
extends /templates/base
|
||||
|
||||
block content
|
||||
.clearfix
|
||||
.col-sm-6.clearfix
|
||||
h2 Account Settings
|
||||
hr
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
i.glyphicon.glyphicon-user.pull-left
|
||||
h3.panel-title
|
||||
a(href="account/settings#me") Me
|
||||
.panel-body
|
||||
dl
|
||||
dt Name
|
||||
dd=me.get('name')
|
||||
dt Email
|
||||
dd abe@lincoln
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
i.glyphicon.glyphicon-picture.pull-left
|
||||
h3.panel-title
|
||||
a(href="account/settings#picture") Picture
|
||||
.panel-body.text-center
|
||||
img#picture(src="#{me.getPhotoURL(150)}" alt="")
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
i.glyphicon.glyphicon-user.pull-left
|
||||
h3.panel-title
|
||||
a(href="account/settings#wizard") Wizard
|
||||
//.panel-body
|
||||
| Lorem Ipsum
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
i.glyphicon.glyphicon-envelope.pull-left
|
||||
h3.panel-title
|
||||
a(href="account/settings#emails") Emails
|
||||
.panel-body
|
||||
.form
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_archmageNews")
|
||||
span General
|
||||
input#email_archmageNews(name="email_archmageNews", type="checkbox", checked=subs.generalNews, disabled="true")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_archmageNews")
|
||||
span.spr(data-i18n="classes.archmage_title")
|
||||
| Archmage
|
||||
span(data-i18n="classes.archmage_title_description")
|
||||
| (Coder)
|
||||
input#email_archmageNews(name="email_archmageNews", type="checkbox", checked=subs.archmageNews, disabled="true")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_artisanNews")
|
||||
span.spr(data-i18n="classes.artisan_title")
|
||||
| Artisan
|
||||
span(data-i18n="classes.artisan_title_description")
|
||||
| (Level Builder)
|
||||
input#email_artisanNews(name="email_artisanNews", type="checkbox", checked=subs.artisanNews, disabled="true")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_adventurerNews")
|
||||
span.spr(data-i18n="classes.adventurer_title")
|
||||
| Adventurer
|
||||
span(data-i18n="classes.adventurer_title_description")
|
||||
| (Level Playtester)
|
||||
input#email_adventurerNews(name="email_adventurerNews", type="checkbox", checked=subs.adventurerNews, disabled="true")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_scribeNews")
|
||||
span.spr(data-i18n="classes.scribe_title")
|
||||
| Scribe
|
||||
span(data-i18n="classes.scribe_title_description")
|
||||
| (Article Editor)
|
||||
input#email_scribeNews(name="email_scribeNews", type="checkbox", checked=subs.scribeNews, disabled="true")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_diplomatNews")
|
||||
span.spr(data-i18n="classes.diplomat_title")
|
||||
| Diplomat
|
||||
span(data-i18n="classes.diplomat_title_description")
|
||||
| (Translator)
|
||||
input#email_diplomatNews(name="email_diplomatNews", type="checkbox", checked=subs.diplomatNews, disabled="true")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="email_ambassadorNews")
|
||||
span.spr(data-i18n="classes.ambassador_title")
|
||||
| Ambassador
|
||||
span(data-i18n="classes.ambassador_title_description")
|
||||
| (Support)
|
||||
input#email_ambassadorNews(name="email_ambassadorNews", type="checkbox", checked=subs.ambassadorNews, disabled="true")
|
||||
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
i.glyphicon.glyphicon-wrench.pull-left
|
||||
h3.panel-title
|
||||
a(href="account/settings#password") Password
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
i.glyphicon.glyphicon-briefcase.pull-left
|
||||
h3.panel-title
|
||||
a(href="account/settings#job-profile") Job Profile
|
||||
.col-sm-6
|
||||
h2 Recently Played
|
||||
hr
|
||||
if !recentlyPlayed
|
||||
div Loading...
|
||||
else if recentlyPlayed.length
|
||||
table.table
|
||||
tr
|
||||
th Level
|
||||
th Last Played
|
||||
th Status
|
||||
each session in recentlyPlayed
|
||||
if session.get('levelName')
|
||||
tr
|
||||
td
|
||||
- var posturl = ''
|
||||
- if (session.get('team')) posturl = '?team=' + session.get('team')
|
||||
a(href="/play/level/#{session.get('levelID') + posturl}")= session.get('levelName') + (session.get('team') ? ' (' + session.get('team') + ')' : '')
|
||||
td= moment(session.get('changed')).fromNow()
|
||||
if session.get('state').complete === true
|
||||
td Completed
|
||||
else if ! session.isMultiplayer()
|
||||
td Unfinished
|
||||
else
|
||||
td
|
||||
|
||||
else
|
||||
.panel.panel-default
|
||||
if !me.isAnonymous()
|
||||
.clearfix
|
||||
.col-sm-6.clearfix
|
||||
h2 Account Settings
|
||||
a.spl(href="settings")
|
||||
i.glyphicon.glyphicon-cog
|
||||
hr
|
||||
.row
|
||||
.col-xs-6
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title
|
||||
i.glyphicon.glyphicon-picture
|
||||
a(href="account/settings#picture") Picture
|
||||
.panel-body.text-center
|
||||
img#picture(src="#{me.getPhotoURL(150)}" alt="")
|
||||
.col-xs-6
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title
|
||||
i.glyphicon.glyphicon-user
|
||||
a(href="account/settings#wizard") Wizard
|
||||
if (wizardSource)
|
||||
.panel-body.text-center
|
||||
img(src="#{wizardSource}")
|
||||
.panel.panel-default.panel-me
|
||||
.panel-heading
|
||||
h3.panel-title
|
||||
i.glyphicon.glyphicon-user
|
||||
a(href="account/settings#me") Me
|
||||
.panel-body
|
||||
div No games played during the past two weeks.
|
||||
|
||||
//block content
|
||||
h2 Account
|
||||
.col-sm-3.text-center
|
||||
img#avatar(src="#{me.getPhotoURL(100)}")
|
||||
h3=me.get('name') || 'Anoner'
|
||||
.col-sm-6
|
||||
dl.dl-horizontal
|
||||
if me.get('firstName') || me.get('lastName')
|
||||
dt Full name
|
||||
dd=me.get('firstName') || '' + ' ' + me.get('lastName') || ''
|
||||
dt Email
|
||||
dd
|
||||
span.spr=me.get('email')
|
||||
//span (subscriptions)
|
||||
hr
|
||||
- var dateCreated = me.get('dateCreated');
|
||||
- var signedCLA = me.get('signedCLA');
|
||||
- console.log(moment)
|
||||
dt Member since
|
||||
dd= moment(dateCreated).format('MMMM Do YYYY')
|
||||
if signedCLA
|
||||
dt Signed CLA
|
||||
dd= moment(signedCLA).format('MMMM Do YYYY')
|
||||
|
||||
// TODO Have social network icons here for easy linking
|
||||
|
||||
.col-sm-3
|
||||
h3 Account
|
||||
ul
|
||||
li
|
||||
a Settings
|
||||
li
|
||||
a Payment
|
||||
h3 Public
|
||||
ul
|
||||
li
|
||||
a Public profile
|
||||
li
|
||||
a Job Profile
|
||||
li
|
||||
a Statistics
|
||||
li
|
||||
a Code
|
||||
table
|
||||
tr
|
||||
th Name
|
||||
td=me.get('name') || 'Anoner'
|
||||
tr
|
||||
th Email
|
||||
td=me.get('email')
|
||||
.panel.panel-default.panel-emails
|
||||
.panel-heading
|
||||
h3.panel-title
|
||||
i.glyphicon.glyphicon-envelope
|
||||
a(href="account/settings#emails") Emails
|
||||
.panel-body
|
||||
if !hasEmailNotes && !hasEmailNews
|
||||
p No email subscriptions.
|
||||
if hasEmailNotes
|
||||
h4 Notifications
|
||||
ul
|
||||
if subs.anyNotes
|
||||
li(data-i18n="account_settings.email_any_notes") Any Notifications
|
||||
if subs.recruitNotes
|
||||
li(data-i18n="account_settings.email_recruit_notes") Job Opportunities
|
||||
if hasEmailNews
|
||||
h4 News
|
||||
ul
|
||||
if (subs.generalNews)
|
||||
li(data-i18n="account_settings.email_announcements") General
|
||||
if (subs.archmageNews)
|
||||
li
|
||||
span(data-i18n="classes.archmage_title")
|
||||
| Archmage
|
||||
span(data-i18n="classes.archmage_title_description")
|
||||
| (Coder)
|
||||
if (subs.artisanNews)
|
||||
li
|
||||
span.spr(data-i18n="classes.artisan_title")
|
||||
| Artisan
|
||||
span(data-i18n="classes.artisan_title_description")
|
||||
| (Level Builder)
|
||||
if (subs.adventurerNews)
|
||||
li
|
||||
span.spr(data-i18n="classes.adventurer_title")
|
||||
| Adventurer
|
||||
span(data-i18n="classes.adventurer_title_description")
|
||||
| (Level Playtester)
|
||||
if (subs.scribeNews)
|
||||
li
|
||||
span.spr(data-i18n="classes.scribe_title")
|
||||
| Scribe
|
||||
span(data-i18n="classes.scribe_title_description")
|
||||
| (Article Editor)
|
||||
if (subs.diplomatNews)
|
||||
li
|
||||
span.spr(data-i18n="classes.diplomat_title")
|
||||
| Diplomat
|
||||
span(data-i18n="classes.diplomat_title_description")
|
||||
| (Translator)
|
||||
if (subs.ambassadorNews)
|
||||
li
|
||||
span.spr(data-i18n="classes.ambassador_title")
|
||||
| Ambassador
|
||||
span(data-i18n="classes.ambassador_title_description")
|
||||
| (Support)
|
||||
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title
|
||||
i.glyphicon.glyphicon-wrench
|
||||
a(href="account/settings#password") Password
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title
|
||||
i.glyphicon.glyphicon-briefcase
|
||||
a(href="account/settings#job-profile") Job Profile
|
||||
.col-sm-6
|
||||
h2 Recently Played
|
||||
hr
|
||||
if !recentlyPlayed
|
||||
div Loading...
|
||||
else if recentlyPlayed.length
|
||||
table.table
|
||||
tr
|
||||
th Level
|
||||
th Last Played
|
||||
th Status
|
||||
each session in recentlyPlayed
|
||||
if session.get('levelName')
|
||||
tr
|
||||
td
|
||||
- var posturl = ''
|
||||
- if (session.get('team')) posturl = '?team=' + session.get('team')
|
||||
a(href="/play/level/#{session.get('levelID') + posturl}")= session.get('levelName') + (session.get('team') ? ' (' + session.get('team') + ')' : '')
|
||||
td= moment(session.get('changed')).fromNow()
|
||||
if session.get('state').complete === true
|
||||
td Completed
|
||||
else if ! session.isMultiplayer()
|
||||
td Unfinished
|
||||
else
|
||||
td
|
||||
|
||||
else
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
div No games played during the past two weeks.
|
||||
|
|
|
@ -6,14 +6,8 @@ block content
|
|||
if user && viewName
|
||||
ol.breadcrumb
|
||||
li
|
||||
a(href="/user/#{user.id}") #{user.displayName()}
|
||||
a(href="/user/#{user.getSlugOrID()}") #{user.displayName()}
|
||||
li.active
|
||||
| #{viewName}
|
||||
if !userLoaded
|
||||
if !user || user.loading
|
||||
| LOADING
|
||||
else if !user
|
||||
// TODO Ruben make this all fancy as soon as we can query users by name
|
||||
| User not found.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ block append content
|
|||
.grid-layout
|
||||
each achievements, category in achievementsByCategory
|
||||
.row
|
||||
h2.achievements-category=category
|
||||
h2.achievement-category-title=category.charAt(0).toUpperCase() + category.slice(1)
|
||||
each achievement, index in achievements
|
||||
- var title = achievement.get('name');
|
||||
- var description = achievement.get('description');
|
||||
|
@ -33,7 +33,7 @@ block append content
|
|||
th Date
|
||||
th Amount
|
||||
th XP
|
||||
each earnedAchievement in earnedAchievements
|
||||
each earnedAchievement in earnedAchievements.models
|
||||
- var achievement = earnedAchievement.get('achievement');
|
||||
tr
|
||||
td= achievement.get('name')
|
||||
|
|
|
@ -13,9 +13,12 @@ block append content
|
|||
div.extra-info Favorite language is
|
||||
strong.spl.spr= favoriteLanguage
|
||||
.btn-group-vertical.profile-menu
|
||||
a.btn.btn-default(href="/user/#{user.get('slug') || user.get('_id')}/profile")
|
||||
a.btn.btn-default(href="/user/#{user.getSlugOrID()}/profile")
|
||||
i.glyphicon.glyphicon-briefcase
|
||||
span Job Profile
|
||||
a.btn.btn-default(href="/user/#{user.getSlugOrID()}/stats")
|
||||
i.glyphicon.glyphicon-certificate
|
||||
span Stats
|
||||
a.btn.btn-default.disabled(href="#")
|
||||
i.glyphicon.glyphicon-pencil
|
||||
span Code
|
||||
|
@ -52,10 +55,6 @@ block append content
|
|||
a(href="/contribute#scribe") Scribe
|
||||
|
||||
.right-column
|
||||
//.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title Achievements
|
||||
.panel-body
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title Singleplayer Levels
|
||||
|
@ -65,9 +64,9 @@ block append content
|
|||
else if (singlePlayerSessions.length)
|
||||
table.table
|
||||
tr
|
||||
th Level
|
||||
th Last Played
|
||||
th Status
|
||||
th.col-xs-4 Level
|
||||
th.col-xs-4 Last Played
|
||||
th.col-xs-4 Status
|
||||
each session in singlePlayerSessions
|
||||
if session.get('levelName')
|
||||
tr
|
||||
|
@ -90,17 +89,43 @@ block append content
|
|||
else if (multiPlayerSessions.length)
|
||||
table.table
|
||||
tr
|
||||
th Level
|
||||
th Team
|
||||
th Last Played
|
||||
th.col-xs-4 Level
|
||||
th.col-xs-4 Last Played
|
||||
th.col-xs-4 Score
|
||||
each session in multiPlayerSessions
|
||||
tr
|
||||
td
|
||||
a(href="/play/level/#{session.get('levelID')}")= session.get('levelName')
|
||||
td= session.get('team')
|
||||
- var posturl = ''
|
||||
- if (session.get('team')) posturl = '?team=' + session.get('team')
|
||||
a(href="/play/level/#{session.get('levelID') + posturl}")= session.get('levelName') + (session.get('team') ? ' (' + session.get('team') + ')' : '')
|
||||
td= moment(session.get('changed')).fromNow()
|
||||
if session.get('state').complete === true
|
||||
td Completed
|
||||
if session.get('totalScore')
|
||||
td= session.get('totalScore') * 100
|
||||
else
|
||||
td Unfinished
|
||||
else
|
||||
.panel-body
|
||||
p No Multiplayer games played yet.
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title Achievements
|
||||
if ! earnedAchievements
|
||||
.panel-body
|
||||
p Loading...
|
||||
else if ! earnedAchievements.length
|
||||
.panel-body
|
||||
p No achievements earned so far.
|
||||
else
|
||||
table.table
|
||||
tr
|
||||
th.col-xs-4 Achievement
|
||||
th.col-xs-4 Last Earned
|
||||
th.col-xs-4 Amount
|
||||
each achievement in earnedAchievements.models
|
||||
tr
|
||||
td= achievement.get('achievementName')
|
||||
td= moment().format("MMMM Do YY", achievement.get('changed'))
|
||||
if achievement.get('achievedAmount')
|
||||
td= achievement.get('achievedAmount')
|
||||
else
|
||||
td
|
||||
|
|
|
@ -4,6 +4,7 @@ template = require 'templates/account/home'
|
|||
User = require 'models/User'
|
||||
AuthModalView = require 'views/modal/AuthModal'
|
||||
RecentlyPlayedCollection = require 'collections/RecentlyPlayedCollection'
|
||||
ThangType = require 'models/ThangType'
|
||||
|
||||
module.exports = class MainAccountView extends View
|
||||
id: 'account-home-view'
|
||||
|
@ -12,15 +13,24 @@ module.exports = class MainAccountView extends View
|
|||
constructor: (options) ->
|
||||
super options
|
||||
return unless me
|
||||
@recentlyPlayed = @supermodel.loadCollection(new RecentlyPlayedCollection(me.get('_id')), 'recentlyPlayed').model
|
||||
@wizardType = ThangType.loadUniversalWizard()
|
||||
@recentlyPlayed = new RecentlyPlayedCollection me.get('_id')
|
||||
@supermodel.loadModel @wizardType, 'thang'
|
||||
@supermodel.loadCollection @recentlyPlayed, 'recentlyPlayed'
|
||||
|
||||
onLoaded: ->
|
||||
super()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.subs = {}
|
||||
c.subs[sub] = 1 for sub in c.me.getEnabledEmails()
|
||||
c.hasEmailNotes = _.any c.me.getEnabledEmails(), (sub) -> sub.contains 'Notes'
|
||||
c.hasEmailNews = _.any c.me.getEnabledEmails(), (sub) -> sub.contains 'News'
|
||||
c.wizardSource = @wizardType.getPortraitSource colorConfig: me.get('wizard')?.colorConfig if @wizardType.loaded
|
||||
c.recentlyPlayed = @recentlyPlayed.models
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
@openModelView new AuthModalView if me.isAnonymous()
|
||||
@openModalView new AuthModalView if me.isAnonymous()
|
||||
|
|
|
@ -80,7 +80,7 @@ module.exports = class AchievementEditView extends RootView
|
|||
$('#achievement-view-inner').notify data, options
|
||||
|
||||
openSaveModal: ->
|
||||
'Maybe later' # TODO
|
||||
'Maybe later' # TODO patch patch patch
|
||||
|
||||
saveAchievement: (e) ->
|
||||
@treema.endExistingEdits()
|
||||
|
|
|
@ -47,13 +47,13 @@ module.exports = class RootView extends CocoView
|
|||
achievedExp = achievement.get 'worth'
|
||||
previousExp = currentExp - achievedExp
|
||||
leveledUp = currentExp - achievedExp < currentLevelExp
|
||||
console.debug 'Leveled up' if leveledUp
|
||||
#console.debug 'Leveled up' if leveledUp
|
||||
alreadyAchievedPercentage = 100 * (previousExp - currentLevelExp) / totalExpNeeded
|
||||
alreadyAchievedPercentage = 0 if alreadyAchievedPercentage < 0 # In case of level up
|
||||
newlyAchievedPercentage = if leveledUp then 100 * (currentExp - currentLevelExp) / totalExpNeeded else 100 * achievedExp / totalExpNeeded
|
||||
|
||||
console.debug "Current level is #{currentLevel} (#{currentLevelExp} xp), next level is #{nextLevel} (#{nextLevelExp} xp)."
|
||||
console.debug "Need a total of #{nextLevelExp - currentLevelExp}, already had #{previousExp} and just now earned #{achievedExp} totalling on #{currentExp}"
|
||||
#console.debug "Current level is #{currentLevel} (#{currentLevelExp} xp), next level is #{nextLevel} (#{nextLevelExp} xp)."
|
||||
#console.debug "Need a total of #{nextLevelExp - currentLevelExp}, already had #{previousExp} and just now earned #{achievedExp} totalling on #{currentExp}"
|
||||
|
||||
alreadyAchievedBar = $("<div class='progress-bar exp-bar-accumulated' style='width:#{alreadyAchievedPercentage}%'></div>")
|
||||
newlyAchievedBar = $("<div data-toggle='tooltip' class='progress-bar exp-bar-new' style='width:#{newlyAchievedPercentage}%'></div>")
|
||||
|
@ -79,7 +79,6 @@ module.exports = class RootView extends CocoView
|
|||
|
||||
showNewAchievement: (achievement, earnedAchievement) ->
|
||||
data = @createNotifyData achievement, earnedAchievement
|
||||
console.debug data
|
||||
options =
|
||||
autoHideDelay: 5000
|
||||
elementPosition: 'top left'
|
||||
|
@ -89,7 +88,6 @@ module.exports = class RootView extends CocoView
|
|||
autoHide: false
|
||||
clickToHide: true
|
||||
|
||||
console.debug 'showing achievement', achievement.get 'name'
|
||||
unless @timeout?
|
||||
$.notify data, options
|
||||
@timeout = 2000
|
||||
|
|
|
@ -9,40 +9,27 @@ module.exports = class UserView extends RootView
|
|||
|
||||
constructor: (@userID, options) ->
|
||||
super options
|
||||
|
||||
@listenTo @, 'userLoaded', @onUserLoaded
|
||||
@listenTo @, 'userNotFound', @ifUserNotFound
|
||||
|
||||
@userID ?= me.id # TODO Ruben really?
|
||||
@fetchUser @userID
|
||||
|
||||
# TODO Ruben make this use the new getByNameOrID as soon as that is merged in
|
||||
fetchUser: (id) ->
|
||||
User.getByID id, {}, true,
|
||||
success: (@user) =>
|
||||
@userLoaded = true
|
||||
@trigger 'userNotFound' unless @user
|
||||
@trigger 'userLoaded', @user
|
||||
error: =>
|
||||
@userLoaded = true
|
||||
@trigger 'userNotFound'
|
||||
if @isMe()
|
||||
@user = me
|
||||
@onLoaded()
|
||||
@user = new User _id: id
|
||||
@supermodel.loadModel @user, 'user'
|
||||
|
||||
getRenderData: ->
|
||||
context = super()
|
||||
context.viewName = @viewName
|
||||
context.user = @user unless @user?.isAnonymous()
|
||||
context.userLoaded = @userLoaded
|
||||
context
|
||||
|
||||
isMe: -> @userID is me.id
|
||||
|
||||
onUserLoaded: ->
|
||||
console.log 'onUserLoaded', @user
|
||||
@render()
|
||||
onLoaded: ->
|
||||
super()
|
||||
|
||||
ifUserNotFound: ->
|
||||
console.warn 'user not found'
|
||||
@render()
|
||||
|
||||
onLoaded: ->
|
||||
super()
|
||||
|
|
|
@ -19,22 +19,22 @@ module.exports = class AchievementsView extends UserView
|
|||
constructor: (userID, options) ->
|
||||
super options, userID
|
||||
|
||||
onUserLoaded: (user) ->
|
||||
@achievements = @supermodel.loadCollection(new AchievementCollection, 'achievements').model
|
||||
@earnedAchievements = @supermodel.loadCollection(new EarnedAchievementCollection(@user), 'earnedAchievements').model
|
||||
super user
|
||||
|
||||
onLoaded: ->
|
||||
console.log @earnedAchievementsy
|
||||
console.log @achievements
|
||||
for earned in @earnedAchievements.models
|
||||
return unless relatedAchievement = _.find @achievements.models, (achievement) ->
|
||||
achievement.get('_id') is earned.get 'achievement'
|
||||
relatedAchievement.set 'unlocked', true
|
||||
earned.set 'achievement', relatedAchievement
|
||||
deferredImages = (achievement.cacheLockedImage() for achievement in @achievements.models when not achievement.get 'unlocked')
|
||||
whenever = $.when deferredImages...
|
||||
whenever.done => @render()
|
||||
unless @achievements or @earnedAchievements
|
||||
@supermodel.resetProgress()
|
||||
@achievements = new AchievementCollection
|
||||
@earnedAchievements = new EarnedAchievementCollection @user.getSlugOrID()
|
||||
@supermodel.loadCollection @achievements, 'achievements'
|
||||
@supermodel.loadCollection @earnedAchievements, 'earnedAchievements'
|
||||
else
|
||||
for earned in @earnedAchievements.models
|
||||
return unless relatedAchievement = _.find @achievements.models, (achievement) ->
|
||||
achievement.get('_id') is earned.get 'achievement'
|
||||
relatedAchievement.set 'unlocked', true
|
||||
earned.set 'achievement', relatedAchievement
|
||||
deferredImages = (achievement.cacheLockedImage() for achievement in @achievements.models when not achievement.get 'unlocked')
|
||||
whenever = $.when deferredImages...
|
||||
whenever.done => @render()
|
||||
super()
|
||||
|
||||
layoutChanged: (e) ->
|
||||
|
@ -47,8 +47,8 @@ module.exports = class AchievementsView extends UserView
|
|||
|
||||
# After user is loaded
|
||||
if @user and not @user.isAnonymous()
|
||||
context.earnedAchievements = @earnedAchievements.models
|
||||
context.achievements = @achievements.models
|
||||
context.earnedAchievements = @earnedAchievements
|
||||
context.achievements = @achievements
|
||||
context.achievementsByCategory = {}
|
||||
for achievement in @achievements.models
|
||||
context.achievementsByCategory[achievement.get('category')] ?= []
|
||||
|
|
|
@ -3,12 +3,13 @@ CocoCollection = require 'collections/CocoCollection'
|
|||
LevelSession = require 'models/LevelSession'
|
||||
template = require 'templates/user/home'
|
||||
{me} = require 'lib/auth'
|
||||
EarnedAchievementCollection = require 'collections/EarnedAchievementCollection'
|
||||
|
||||
class LevelSessionsCollection extends CocoCollection
|
||||
model: LevelSession
|
||||
|
||||
constructor: (userID) ->
|
||||
@url = "/db/user/#{userID}/level.sessions?project=state.complete,levelID,levelName,changed,team,submittedCodeLanguage&order=-1"
|
||||
@url = "/db/user/#{userID}/level.sessions?project=state.complete,levelID,levelName,changed,team,submittedCodeLanguage,totalScore&order=-1"
|
||||
super()
|
||||
|
||||
module.exports = class MainUserView extends UserView
|
||||
|
@ -20,7 +21,8 @@ module.exports = class MainUserView extends UserView
|
|||
|
||||
getRenderData: ->
|
||||
context = super()
|
||||
if @user
|
||||
if @levelSessions and @levelSessions.loaded
|
||||
console.debug 'yep sessions loaded'
|
||||
singlePlayerSessions = []
|
||||
multiPlayerSessions = []
|
||||
languageCounts = {}
|
||||
|
@ -39,11 +41,19 @@ module.exports = class MainUserView extends UserView
|
|||
context.singlePlayerSessions = singlePlayerSessions
|
||||
context.multiPlayerSessions = multiPlayerSessions
|
||||
context.favoriteLanguage = favoriteLanguage
|
||||
if @earnedAchievements and @earnedAchievements.loaded
|
||||
console.debug 'earned achievements loaded'
|
||||
context.earnedAchievements = @earnedAchievements
|
||||
context
|
||||
|
||||
onUserLoaded: (user) ->
|
||||
@levelSessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'levelSessions').model
|
||||
super user
|
||||
|
||||
onLoaded: ->
|
||||
console.debug @earnedAchievements
|
||||
console.debug @earnedAchievements?.loaded
|
||||
if @user.loaded and not @earnedAchievements
|
||||
@supermodel.resetProgress()
|
||||
#@levelSessions = new LevelSessionsCollection @user.getSlugOrID()
|
||||
@earnedAchievements = new EarnedAchievementCollection @user.getSlugOrID()
|
||||
#@supermodel.loadCollection @levelSessions, 'levelSessions'
|
||||
@supermodel.loadCollection @earnedAchievements, 'earnedAchievements'
|
||||
|
||||
super()
|
||||
|
|
BIN
public/images/achievements/achievement_background_light.png
Normal file
BIN
public/images/achievements/achievement_background_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 9.6 KiB |
BIN
public/images/achievements/star.png
Normal file
BIN
public/images/achievements/star.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.7 KiB |
|
@ -45,7 +45,7 @@ AchievementSchema.statics.loadAchievements = (done) ->
|
|||
category = achievement.get 'collection'
|
||||
AchievementSchema.statics.earnedAchievements[category] = [] unless category of AchievementSchema.statics.earnedAchievements
|
||||
AchievementSchema.statics.earnedAchievements[category].push achievement
|
||||
done(AchievementSchema.statics.earnedAchievements) if done?
|
||||
done?(AchievementSchema.statics.earnedAchievements)
|
||||
|
||||
AchievementSchema.statics.getLoadedAchievements = ->
|
||||
AchievementSchema.statics.earnedAchievements
|
||||
|
|
|
@ -29,7 +29,6 @@ class EarnedAchievementHandler extends Handler
|
|||
achievementIDs = (thing for thing in callbackOrSlugsOrIDs when Handler.isID(thing))
|
||||
else # just a callback
|
||||
callback = callbackOrSlugsOrIDs
|
||||
callback = if callback then callback else -> # Make a dummy just for ease of coding
|
||||
onFinished = -> callback arguments...
|
||||
|
||||
filter = {}
|
||||
|
@ -40,13 +39,13 @@ class EarnedAchievementHandler extends Handler
|
|||
|
||||
# Fetch all relevant achievements
|
||||
Achievement.find filter, (err, achievements) ->
|
||||
callback err if err?
|
||||
callback new Error 'No achievements to recalculate' unless achievements.length
|
||||
callback?(err) if err?
|
||||
callback?(new Error 'No achievements to recalculate') unless achievements.length
|
||||
log.info "Recalculating a total of #{achievements.length} achievements..."
|
||||
|
||||
# Fetch every single user
|
||||
User.find {}, (err, users) ->
|
||||
callback err if err?
|
||||
callback?(err) if err?
|
||||
log.info "for a total of #{users.length} users."
|
||||
|
||||
async.each users, ((user, doneWithUser) ->
|
||||
|
|
|
@ -57,12 +57,12 @@ PatchSchema.methods.isMiscPatch = ->
|
|||
|
||||
# Keep track of when a patch is pending and newly approved.
|
||||
PatchSchema.path('status').set (newVal) ->
|
||||
@set '_wasPending', @status is 'pending' and newVal isnt 'pending'
|
||||
@set '_newlyAccepted', newVal is 'accepted' and not @get('_newlyAccepted') # Only true on the first accept
|
||||
@set 'wasPending', @status is 'pending' and newVal isnt 'pending'
|
||||
@set 'newlyAccepted', newVal is 'accepted' and not @get('newlyAccepted') # Only true on the first accept
|
||||
newVal
|
||||
|
||||
PatchSchema.methods.isNewlyAccepted = -> @get('_newlyAccepted')
|
||||
PatchSchema.methods.wasPending = -> @get '_wasPending'
|
||||
PatchSchema.methods.isNewlyAccepted = -> @get('newlyAccepted')
|
||||
PatchSchema.methods.wasPending = -> @get 'wasPending'
|
||||
|
||||
PatchSchema.pre 'save', (next) ->
|
||||
User = require '../users/User'
|
||||
|
|
|
@ -142,7 +142,7 @@ UserSchema.statics.incrementStat = (id, statName, done, inc=1) ->
|
|||
|
||||
UserSchema.methods.incrementStat = (statName, done, inc=1) ->
|
||||
@set statName, (@get(statName) or 0) + inc
|
||||
@save (err) -> done err if done?
|
||||
@save (err) -> done?(err)
|
||||
|
||||
UserSchema.statics.unconflictName = unconflictName = (name, done) ->
|
||||
User.findOne {slug: _.str.slugify(name)}, (err, otherUser) ->
|
||||
|
|
Loading…
Reference in a new issue