diff --git a/app/directives/page-state-header/page-state-header.directive.js b/app/directives/page-state-header/page-state-header.directive.js index 23030ba96..990a2b53b 100644 --- a/app/directives/page-state-header/page-state-header.directive.js +++ b/app/directives/page-state-header/page-state-header.directive.js @@ -16,12 +16,12 @@ import _ from 'lodash' hideMoney: '=', defaultState: '@' }, - controller: ['CONSTANTS', '$rootScope', '$scope', 'ProfileService', 'logger', '$state', pageStateHeader], + controller: ['CONSTANTS', '$rootScope', '$scope', 'ProfileService', 'logger', '$state', 'ChallengeService', '$q', 'UserService', 'BadgeService', pageStateHeader], controllerAs: 'vm' } }) - function pageStateHeader(CONSTANTS, $rootScope, $scope, ProfileService, logger, $state) { + function pageStateHeader(CONSTANTS, $rootScope, $scope, ProfileService, logger, $state, ChallengeService, $q, UserService, BadgeService) { var vm = this vm.backHandler = backHandler @@ -35,13 +35,12 @@ import _ from 'lodash' function activate() { vm.handle = $scope.handle vm.profile = null - vm.handleColor = null $scope.hideMoney = _.get($scope, 'hideMoney', true) vm.previousStateName = null vm.previousStateLabel = null vm.previousState = null - vm.showBackLink = _.get($scope, 'showBackLink', false) - vm.loading = true + vm.dashboardBadgeName = null + // identifies the previous state if ($scope.$root.previousState && $scope.$root.previousState.name.length > 0) { @@ -65,14 +64,32 @@ import _ from 'lodash' // gets member's profile ProfileService.getUserProfile(vm.handle).then(function(profile) { vm.profile = profile - vm.handleColor = ProfileService.getUserHandleColor(vm.profile) - if (!$scope.hideMoney) { - displayMoneyEarned(vm.handle) - } else { - vm.loading = false - } + // get members dashboard badge + UserService.getV2UserProfile(vm.handle).then(function(resp) { + + var dashboardAchievement = _filterDashboardAchievement(resp.Achievements || [])[0] + if (dashboardAchievement) { + //Get dashboard badges + vm.dashboardBadge = BadgeService.getAchievementVm(dashboardAchievement) + } + }) + }) + + // get member's challenges to display number of active challenges + $q.all([ + ChallengeService.getUserMarathonMatches(vm.handle, { filter: 'status=active' }), + ChallengeService.getUserChallenges(vm.handle, { filter: 'status=active' }) + ]).then(function(challenges){ + var marathonMatches = challenges[0] + var devDesignChallenges = challenges[1] + + vm.activeChallenges = marathonMatches.length + devDesignChallenges.length + }) + + displayMoneyEarned(vm.handle) + } function backHandler() { @@ -100,15 +117,21 @@ import _ from 'lodash' if (!vm.moneyEarned) { $scope.hideMoney = true } - - vm.loading = false }) .catch(function(err) { $scope.hideMoney = true - vm.loading = false - logger.error('Could not get user financial information', err) }) } + + function _filterDashboardAchievement(achievements) { + //Currently only one batch is shown on the dashboard + vm.dashboardBadgeName = 'SRM Engagement Honor' + + return achievements.filter(function(achievement) { + return (achievement.description === vm.dashboardBadgeName) + }) + } + } })() diff --git a/app/directives/page-state-header/page-state-header.jade b/app/directives/page-state-header/page-state-header.jade index 2d440713c..9bbe1e0bb 100644 --- a/app/directives/page-state-header/page-state-header.jade +++ b/app/directives/page-state-header/page-state-header.jade @@ -6,20 +6,15 @@ div(ng-transclude) .info - .pic - a(ui-sref="profile.about({userHandle: vm.profile.handle})") - img.profile-circle(ng-if="vm.profile.photoURL", ng-src="{{vm.profile.photoURL}}") - - img.profile-circle(ng-if="!vm.profile.photoURL", src=require("../../../assets/images/ico-user-default.svg")) - - .user-metrics(id="metrics", ng-hide="vm.loading") - a.handle(style="color:{{vm.handleColor}};", ui-sref="profile.about({userHandle: vm.profile.handle})") {{vm.profile.handle}} - - .money-earned(ng-hide="hideMoney") + .item + .value + p(ng-bind="vm.activeChallenges") + .title + p Active Challenges + .item(ng-if="!hideMoney") + .value p.number(ng-bind="vm.moneyEarned | currency:'$':0") - - p Earned - - .back-link(ng-if="showBackLink && vm.previousStateLabel") - a(ng-click="vm.backHandler()") Back to {{vm.previousStateLabel}} - + .title + p Won in Prizes + .badgeItem(ng-if="vm.dashboardBadge") + .badge(ng-class="(vm.dashboardBadge.specificClass || vm.dashboardBadge.groupClass) + ' ' + (vm.dashboardBadge.type) + 'Badge'" title='{{vm.dashboardBadgeName}}') \ No newline at end of file diff --git a/app/profile/badges/badges.controller.js b/app/profile/badges/badges.controller.js index f99750f43..2edfe390c 100644 --- a/app/profile/badges/badges.controller.js +++ b/app/profile/badges/badges.controller.js @@ -1,673 +1,33 @@ import angular from 'angular' -import moment from 'moment-timezone' (function () { 'use strict' angular.module('tc.profile').controller('BadgesController', BadgeCtrl) - BadgeCtrl.$inject = ['$scope', 'CONSTANTS', 'ProfileService', 'UserService', 'userHandle', 'profile'] + BadgeCtrl.$inject = ['$scope', 'UserService', 'userHandle', 'profile', 'BadgeService'] // The controller for badges section of member-profile page. - function BadgeCtrl($scope, CONSTANTS, ProfileService, UserService, userHandle, profile) { - $scope.achievements = profile.badges.Achievements + function BadgeCtrl($scope, UserService, userHandle, profile, BadgeService) { + $scope.achievements = profile.badges.Achievements || [] var badgeCtrl = this // Use logged in user's handle for showing badges if not injected into the controller badgeCtrl.userHandle = userHandle ? userHandle : UserService.getUserIdentity().username - badgeCtrl.init($scope) - badgeCtrl.mapBadges() badgeCtrl.profile = profile - badgeCtrl.dealWithBadgeData($scope, ProfileService) - } - - // Deal with badge data when we have the user profile ready. - BadgeCtrl.prototype.dealWithBadgeData = function($scope, ProfileService){ - var badgeCtrl = this - // The service method getUser( handle ) already contains achievements information. - // So we don't need another more service method here. - - // Some data is not available, so lets exclude them. - // var excluded_badgesID = [1,6, 11, 16, 21, 52, 1000, 1001, 1002, 1003, 1004, 1005, 1006] - - if ($scope.achievements) { - angular.forEach($scope.achievements, function(achievement){ - var desc = achievement.description - // Fix Studio Badges - if(badgeCtrl.map[achievement.description] === undefined && desc.indexOf('Studio ') === 0) { - desc = desc.substring(7) - } - // Fix Studio bad badge name - if(desc === 'Fifty Milestone Prize' || desc === 'One Hundred Milestone Prize' || desc === 'Two Hundred And Fifty Milestone Prize') { - desc = desc + 's' - } - if(desc.indexOf('Designer of the Month') !== -1) { - desc = 'Designer of the Month' - } - if(desc.indexOf('Member of the Month') !== -1) { - desc = 'Member of the Month' - } - var value = badgeCtrl.map[desc] - // Activate all active badges. - if(value){ - value.date = badgeCtrl.formatDate(achievement.date) - value.active = true - if(achievement.description.indexOf('Studio ') === 0) { - value.isStudio = true - } - } - }) - } - } - // Construct a map containing all badges. - BadgeCtrl.prototype.mapBadges = function(){ - var badgeCtrl = this - badgeCtrl.map = {} - angular.forEach(badgeCtrl.achievementGroups, function(achievementGroup){ - angular.forEach(achievementGroup.specificAchievements, function(achievement){ - achievement.id = achievementGroup.id - badgeCtrl.map[achievement.name] = achievement - }) - }) - angular.forEach(badgeCtrl.singleAchievements, function(achievement){ - badgeCtrl.map[achievement.name] = achievement - }) - } - - // Convert the date with format like 'Sep 09,2013' - BadgeCtrl.prototype.formatDate = function(date) { - // Some function is passing in undefined timezone_string variable causing js errors, - // so check if undefined and set default: - if (typeof timezone_string === 'undefined') { - var timezone_string = 'America/New_York' // lets set to TC timezone - } - return moment(date).tz(timezone_string).format('MMM DD, YYYY') + var achievementsVm = BadgeService.buildAllAchievementsVm($scope.achievements) + badgeCtrl.achievementGroups = achievementsVm.achievementGroups + + //Dashboard badges shoudn't be displyed on public profile page + badgeCtrl.singleAchievements = removeDashBoardAchivements(achievementsVm.singleAchievements) } - // Construct the data 'currentlyEarned'. - BadgeCtrl.prototype.populateData = function(destination, count){ - var quantifier = '' - switch(destination.id){ - case '1': - quantifier = 'Post' - break - case '6': - quantifier = 'Submission' - break - case '11': - quantifier = 'Prize' - break - case '16': - case '117': - quantifier = 'Placement' - break - case '89': - quantifier = 'SRM' - break - case '99': - case '126': - case '127': - quantifier = 'Problem' - break - default: - quantifier = 'Win' - break - } - - if (count && count > 1) { - quantifier += 's' - } - if(count){ - destination.currentlyEarned = count + ' ' + quantifier - } + function removeDashBoardAchivements(singleAchievements){ + var dashboardBadgeName = 'SRM Engagement Honor' + return singleAchievements.filter(function(achievement){ + return (achievement.name != dashboardBadgeName) + }) } - // Initialize the data array needed by badge section. - BadgeCtrl.prototype.init = function($scope){ - this.scope = $scope - - this.achievementGroups = - [ - { - id : 1, - groupClass : 'Forum-Posts', - specificAchievements : [ - { - name : 'First Forum Post', - active : false, - specificClass : 'Forum-Posts-1' - }, - { - name : 'One Hundred Forum Posts', - active : false, - specificClass : 'Forum-Posts-100' - }, - { - name : 'Five Hundred Forum Posts', - active : false, - specificClass : 'Forum-Posts-500' - }, - { - name : 'One Thousand Forum Posts', - active : false, - specificClass : 'Forum-Posts-1000' - }, - { - name : 'Five Thousand Forum Posts', - active : false, - specificClass : 'Forum-Posts-5000' - } - ] - }, - { - id : 89, - groupClass : 'Rated-SRMs', - specificAchievements : [ - { - name : 'First Rated Algorithm Competition', - active : false, - specificClass : 'Rated-SRMs-1' - }, - { - name : 'Five Rated Algorithm Competitions', - active : false, - specificClass : 'Rated-SRMs-5' - }, - { - name : 'Twenty Five Rated Algorithm Competitions', - active : false, - specificClass : 'Rated-SRMs-25' - }, - { - name : 'One Hundred Rated Algorithm Competitions', - active : false, - specificClass : 'Rated-SRMs-100' - }, - { - name : 'Three Hundred Rated Algorithm Competitions', - active : false, - specificClass : 'Rated-SRMs-300' - } - ] - }, - { - id : 94, - groupClass : 'SRM-Room-Wins', - specificAchievements : [ - { - name : 'First SRM Room Win (Any Division)', - active : false, - specificClass : 'SRM-Room-Wins-1' - }, - { - name : 'Five SRM Room Wins (Any Division)', - active : false, - specificClass : 'SRM-Room-Wins-5' - }, - { - name : 'Twenty SRM Room Wins (Any Division)', - active : false, - specificClass : 'SRM-Room-Wins-20' - }, - { - name : 'Fifty SRM Room Wins (Any Division)', - active : false, - specificClass : 'SRM-Room-Wins-50' - }, - { - name : 'One Hundred SRM Room Wins (Any Division)', - active : false, - specificClass : 'SRM-Room-Wins-100' - } - ] - }, - { - id : 99, - groupClass : 'Solved-SRM-Problems', - specificAchievements : [ - { - name : 'First Solved Algorithm Problem', - active : false, - specificClass : 'Solved-SRM-Problems-1' - }, - { - name : 'Ten Solved Algorithm Problems', - active : false, - specificClass : 'Solved-SRM-Problems-10' - }, - { - name : 'Fifty Solved Algorithm Problems', - active : false, - specificClass : 'Solved-SRM-Problems-50' - }, - { - name : 'Two Hundred Solved Algorithm Problems', - active : false, - specificClass : 'Solved-SRM-Problems-200' - }, - { - name : 'Five Hundred Solved Algorithm Problems', - active : false, - specificClass : 'Solved-SRM-Problems-500' - } - ] - }, - { - id : 104, - groupClass : 'Successful-Challenges', - specificAchievements : [ - { - name : 'First Successful Challenge', - active : false, - specificClass : 'Successful-Challenges-1' - }, - { - name : 'Five Successful Challenges', - active : false, - specificClass : 'Successful-Challenges-5' - }, - { - name : 'Twenty Five Successful Challenges', - active : false, - specificClass : 'Successful-Challenges-25' - }, - { - name : 'One Hundred Successful Challenges', - active : false, - specificClass : 'Successful-Challenges-100' - }, - { - name : 'Two Hundred Successful Challenges', - active : false, - specificClass : 'Successful-Challenges-250' - } - ] - }, - { - id : 113, - groupClass : 'Marathon-Matches', - specificAchievements : [ - { - name : 'First Marathon Competition', - active : false, - specificClass : 'Marathon-Matches-1' - }, - { - name : 'Three Marathon Competitions', - active : false, - specificClass : 'Marathon-Matches-3' - }, - { - name : 'Ten Marathon Competitions', - active : false, - specificClass : 'Marathon-Matches-10' - }, - { - name : 'Twenty Marathon Competitions', - active : false, - specificClass : 'Marathon-Matches-20' - }, - { - name : 'Fifty Marathon Competitions', - active : false, - specificClass : 'Marathon-Matches-50' - } - ] - }, - { - id : 117, - groupClass : 'Marathon-Top-5-Placements', - specificAchievements : [ - { - name : 'First Marathon Top-5 Placement', - active : false, - specificClass : 'Marathon-Top-5-Placements-1' - }, - { - name : 'Two Marathon Top-5 Placements', - active : false, - specificClass : 'Marathon-Top-5-Placements-2' - }, - { - name : 'Four Marathon Top-5 Placements', - active : false, - specificClass : 'Marathon-Top-5-Placements-4' - }, - { - name : 'Eight Marathon Top-5 Placements', - active : false, - specificClass : 'Marathon-Top-5-Placements-8' - }, - { - name : 'Sixteen Marathon Top-5 Placements', - active : false, - specificClass : 'Marathon-Top-5-Placements-16' - } - ] - }, - { - id : 6, - groupClass : 'Passing-Submissions', - specificAchievements : [ - { - name : 'First Passing Submission', - active : false, - specificClass : 'Passing-Submissions-1' - }, - { - name : 'Fifty Passing Submissions', - active : false, - specificClass : 'Passing-Submissions-50' - }, - { - name : 'One Hundred Passing Submissions', - active : false, - specificClass : 'Passing-Submissions-100' - }, - { - name : 'Two Hundred And Fifty Passing Submissions', - active : false, - specificClass : 'Passing-Submissions-250' - }, - { - name : 'Five Hundred Passing Submissions', - active : false, - specificClass : 'Passing-Submissions-500' - } - ] - }, - { - id : 11, - groupClass : 'Checkpoint-Prizes', - specificAchievements : [ - { - name : 'First Milestone Prize', - active : false, - specificClass : 'Checkpoint-Prizes-1' - }, - { - name : 'Fifty Milestone Prizes', - active : false, - specificClass : 'Checkpoint-Prizes-50' - }, - { - name : 'One Hundred Milestone Prizes', - active : false, - specificClass : 'Checkpoint-Prizes-100' - }, - { - name : 'Two Hundred And Fifty Milestone Prizes', - active : false, - specificClass : 'Checkpoint-Prizes-250' - }, - { - name : 'Five Hundred Milestone Prizes', - active : false, - specificClass : 'Checkpoint-Prizes-500' - } - ] - }, - { - id : 16, - groupClass : 'Winning-Placements', - specificAchievements : [ - { - name : 'First Placement', - active : false, - specificClass : 'Winning-Placements-1' - }, - { - name : 'Twenty Five Placements', - active : false, - specificClass : 'Winning-Placements-25' - }, - { - name : 'Fifty Placements', - active : false, - specificClass : 'Winning-Placements-50' - }, - { - name : 'One hundred Placements', - active : false, - specificClass : 'Winning-Placements-100' - }, - { - name : 'Two Hundred And Fifty Placements', - active : false, - specificClass : 'Winning-Placements-250' - } - ] - }, - { - id : 21, - groupClass : 'First-Place-Wins', - specificAchievements : [ - { - name : 'First Win', - active : false, - specificClass : 'First-Place-Wins-1' - }, - { - name : 'Twenty Five First Placement Win', - active : false, - specificClass : 'First-Place-Wins-25' - }, - { - name : 'Fifty First Placement Win', - active : false, - specificClass : 'First-Place-Wins-50' - }, - { - name : 'One Hundred First Placement Win', - active : false, - specificClass : 'First-Place-Wins-100' - }, - { - name : 'Two Hundred And Fifty First Placement Win', - active : false, - specificClass : 'First-Place-Wins-250' - } - ] - }, - { - id : 0, - groupClass : 'HP-Badges-Level-1', - specificAchievements : [ - { - name : 'Getting Started', - active : false, - specificClass : 'Getting-Started' - }, - { - name : 'Novice', - active : false, - specificClass : 'Novice' - }, - { - name : 'Journeyman', - active : false, - specificClass : 'Journeyman' - }, - { - name : 'Expert', - active : false, - specificClass : 'Expert' - } - ] - }, - { - id : 0, - groupClass : 'HP-Badges-Level-2', - specificAchievements : [ - { - name : 'Master', - active : false, - specificClass : 'Master' - }, - { - name : 'Grand Master', - active : false, - specificClass : 'Grand-Master' - }, - { - name : 'Paragon', - active : false, - specificClass : 'Paragon' - }, - { - name : 'Grand Paragon', - active : false, - specificClass : 'Grand-Paragon' - }, - { - name : 'Social Evangelist', - active : false, - specificClass : 'Social-Evangelist' - } - ] - } - ] - this.singleAchievements = - [ - { - id : 121, - name : 'Marathon Match Winner', - groupClass : 'Marathon-Match-Winner', - active : false - }, - { - id : 122, - name : 'Algorithm Target', - groupClass : 'Algorithm-Target', - active : false - }, - { - id : 119, - name : 'SRM Winner Div 1', - groupClass : 'SRM-Winner-Div-1', - active : false - }, - { - id : 120, - name : 'SRM Winner Div 2', - groupClass : 'SRM-Winner-Div-2', - active : false - }, - { - id : 127, - name : 'Solved Hard Div2 Problem in SRM', - groupClass : 'Solved-Hard-Div2-Problem-in-SRM', - active : false - }, - { - id : 126, - name : 'Solved Hard Div1 Problem in SRM', - groupClass : 'Solved-Hard-Div1-Problem-in-SRM', - active : false - }, - { - id : 51, - name : 'Digital Run Winner', - groupClass : 'Digital-Run-Winner', - active : false - }, - { - id : 52, - name : 'Digital Run Top Five', - groupClass : 'Digital-Run-Top-5', - active : false - }, - { - id : 1, - name : 'Two Hundred Successful Challenges', - groupClass : 'Successful-Challenges-200', - active : false - }, - { - id : 129, - name : 'CoECI Client Badge', - groupClass : 'CoECI-Client-Badge', - active : false - }, - { - id : 0, - name : 'TopCoder Reviewer', - groupClass : 'TopCoder-Reviewer', - active : false - }, - { - id : 1000, - name : 'Studio Reviewer', - groupClass : 'Studio-Reviewer', - active : false - }, - { - id : 1000, - name : 'Studio Cup Top Five', - groupClass : 'Studio-Cup-Top-5', - active : false - }, - { - id : 1001, - name : 'Studio Cup Winner', - groupClass : 'Studio-Cup-Winner', - active : false - }, - { - id : 1002, - name : 'Studio Spec Reviewer', - groupClass : 'Studio-Spec-Reviewer', - active : false - }, - { - id : 1003, - name : 'Studio Screener', - groupClass : 'Studio-Screener', - active : false - }, - { - id : 1003, - name : 'Studio Spirit', - groupClass : 'Studio-Spirit', - active : false - }, - { - id : 1004, - name : 'Studio Mentor', - groupClass : 'Studio-Mentor', - active : false - }, - { - id : 1005, - name : 'Member of the Month', - groupClass : 'Member-of-the-Month', - active : false - }, - { - id : 1006, - name : 'Designer of the Month', - groupClass : 'Member-of-the-Month', - active : false - }, - { - id: 1007, - name: 'Crowd for Good', - groupClass: 'Crowd-for-Good', - active: false - }, - { - id: 1008, - name: 'Predix Community', - groupClass: 'Predix-Community', - active: false - }, - { - id: 1009, - name: 'iOS Community', - groupClass: 'iOS-Community', - active: false - } - ] - } })() diff --git a/app/services/badge.service.js b/app/services/badge.service.js new file mode 100644 index 000000000..4e871a0c0 --- /dev/null +++ b/app/services/badge.service.js @@ -0,0 +1,664 @@ +import angular from 'angular' +import moment from 'moment-timezone' + +(function() { + 'use strict' + + angular.module('tc.services').factory('BadgeService', BadgeService) + + BadgeService.$inject = [] + + function BadgeService() { + var factory = this + + _init() + _createMap() + + return { + getAchievementVm: getAchievementVm, + buildAllAchievementsVm: buildAllAchievementsVm + } + + //Returns the vm for a particular achivement + function getAchievementVm(achievement) { + var desc = achievement.description + desc = _fixBadgeDescriptionIfNecessary(desc) + + var value = factory.map[desc] + value.date = _formatDate(achievement.date) + value.active = true + if(achievement.description.indexOf('Studio ') === 0) { + value.isStudio = true + } + + value.type = value.specificClass ? 'group' : 'single' + + return value + } + + // Returns the convenient view model for all achievements with css class names and active indicator and formated date + function buildAllAchievementsVm(achievements) { + angular.forEach(achievements, function(achievement){ + var desc = achievement.description + desc = _fixBadgeDescriptionIfNecessary(desc) + + var value = factory.map[desc] + // Activate all active badges. + if(value){ + value.date = _formatDate(achievement.date) + value.active = true + if(achievement.description.indexOf('Studio ') === 0) { + value.isStudio = true + } + } + }) + + return { + achievementGroups: factory.achievementGroups, + singleAchievements: factory.singleAchievements + } + + } + + function _fixBadgeDescriptionIfNecessary(desc) { + // Fix Studio Badges + if(factory.map[desc] === undefined && desc.indexOf('Studio ') === 0) { + desc = desc.substring(7) + } + // Fix Studio bad badge name + if(desc === 'Fifty Milestone Prize' || desc === 'One Hundred Milestone Prize' || desc === 'Two Hundred And Fifty Milestone Prize') { + desc = desc + 's' + } + if(desc.indexOf('Designer of the Month') !== -1) { + desc = 'Designer of the Month' + } + if(desc.indexOf('Member of the Month') !== -1) { + desc = 'Member of the Month' + } + + return desc + } + + // Convert the date with format like 'Sep 09,2013' + function _formatDate(date) { + // Some function is passing in undefined timezone_string variable causing js errors, + // so check if undefined and set default: + if (typeof timezone_string === 'undefined') { + var timezone_string = 'America/New_York' // lets set to TC timezone + } + return moment(date).tz(timezone_string).format('MMM DD, YYYY') + } + + // Construct a map containing all badges. + function _createMap() { + var map = {} + angular.forEach(factory.achievementGroups, function(achievementGroup){ + angular.forEach(achievementGroup.specificAchievements, function(achievement){ + achievement.id = achievementGroup.id + map[achievement.name] = achievement + }) + }) + angular.forEach(factory.singleAchievements, function(achievement){ + map[achievement.name] = achievement + }) + + factory.map = map + } + + // Initialize the data array needed by badge section. + function _init() { + factory.achievementGroups = + [ + { + id : 1, + groupClass : 'Forum-Posts', + specificAchievements : [ + { + name : 'First Forum Post', + active : false, + specificClass : 'Forum-Posts-1' + }, + { + name : 'One Hundred Forum Posts', + active : false, + specificClass : 'Forum-Posts-100' + }, + { + name : 'Five Hundred Forum Posts', + active : false, + specificClass : 'Forum-Posts-500' + }, + { + name : 'One Thousand Forum Posts', + active : false, + specificClass : 'Forum-Posts-1000' + }, + { + name : 'Five Thousand Forum Posts', + active : false, + specificClass : 'Forum-Posts-5000' + } + ] + }, + { + id : 89, + groupClass : 'Rated-SRMs', + specificAchievements : [ + { + name : 'First Rated Algorithm Competition', + active : false, + specificClass : 'Rated-SRMs-1' + }, + { + name : 'Five Rated Algorithm Competitions', + active : false, + specificClass : 'Rated-SRMs-5' + }, + { + name : 'Twenty Five Rated Algorithm Competitions', + active : false, + specificClass : 'Rated-SRMs-25' + }, + { + name : 'One Hundred Rated Algorithm Competitions', + active : false, + specificClass : 'Rated-SRMs-100' + }, + { + name : 'Three Hundred Rated Algorithm Competitions', + active : false, + specificClass : 'Rated-SRMs-300' + } + ] + }, + { + id : 94, + groupClass : 'SRM-Room-Wins', + specificAchievements : [ + { + name : 'First SRM Room Win (Any Division)', + active : false, + specificClass : 'SRM-Room-Wins-1' + }, + { + name : 'Five SRM Room Wins (Any Division)', + active : false, + specificClass : 'SRM-Room-Wins-5' + }, + { + name : 'Twenty SRM Room Wins (Any Division)', + active : false, + specificClass : 'SRM-Room-Wins-20' + }, + { + name : 'Fifty SRM Room Wins (Any Division)', + active : false, + specificClass : 'SRM-Room-Wins-50' + }, + { + name : 'One Hundred SRM Room Wins (Any Division)', + active : false, + specificClass : 'SRM-Room-Wins-100' + } + ] + }, + { + id : 99, + groupClass : 'Solved-SRM-Problems', + specificAchievements : [ + { + name : 'First Solved Algorithm Problem', + active : false, + specificClass : 'Solved-SRM-Problems-1' + }, + { + name : 'Ten Solved Algorithm Problems', + active : false, + specificClass : 'Solved-SRM-Problems-10' + }, + { + name : 'Fifty Solved Algorithm Problems', + active : false, + specificClass : 'Solved-SRM-Problems-50' + }, + { + name : 'Two Hundred Solved Algorithm Problems', + active : false, + specificClass : 'Solved-SRM-Problems-200' + }, + { + name : 'Five Hundred Solved Algorithm Problems', + active : false, + specificClass : 'Solved-SRM-Problems-500' + } + ] + }, + { + id : 104, + groupClass : 'Successful-Challenges', + specificAchievements : [ + { + name : 'First Successful Challenge', + active : false, + specificClass : 'Successful-Challenges-1' + }, + { + name : 'Five Successful Challenges', + active : false, + specificClass : 'Successful-Challenges-5' + }, + { + name : 'Twenty Five Successful Challenges', + active : false, + specificClass : 'Successful-Challenges-25' + }, + { + name : 'One Hundred Successful Challenges', + active : false, + specificClass : 'Successful-Challenges-100' + }, + { + name : 'Two Hundred Successful Challenges', + active : false, + specificClass : 'Successful-Challenges-250' + } + ] + }, + { + id : 113, + groupClass : 'Marathon-Matches', + specificAchievements : [ + { + name : 'First Marathon Competition', + active : false, + specificClass : 'Marathon-Matches-1' + }, + { + name : 'Three Marathon Competitions', + active : false, + specificClass : 'Marathon-Matches-3' + }, + { + name : 'Ten Marathon Competitions', + active : false, + specificClass : 'Marathon-Matches-10' + }, + { + name : 'Twenty Marathon Competitions', + active : false, + specificClass : 'Marathon-Matches-20' + }, + { + name : 'Fifty Marathon Competitions', + active : false, + specificClass : 'Marathon-Matches-50' + } + ] + }, + { + id : 117, + groupClass : 'Marathon-Top-5-Placements', + specificAchievements : [ + { + name : 'First Marathon Top-5 Placement', + active : false, + specificClass : 'Marathon-Top-5-Placements-1' + }, + { + name : 'Two Marathon Top-5 Placements', + active : false, + specificClass : 'Marathon-Top-5-Placements-2' + }, + { + name : 'Four Marathon Top-5 Placements', + active : false, + specificClass : 'Marathon-Top-5-Placements-4' + }, + { + name : 'Eight Marathon Top-5 Placements', + active : false, + specificClass : 'Marathon-Top-5-Placements-8' + }, + { + name : 'Sixteen Marathon Top-5 Placements', + active : false, + specificClass : 'Marathon-Top-5-Placements-16' + } + ] + }, + { + id : 6, + groupClass : 'Passing-Submissions', + specificAchievements : [ + { + name : 'First Passing Submission', + active : false, + specificClass : 'Passing-Submissions-1' + }, + { + name : 'Fifty Passing Submissions', + active : false, + specificClass : 'Passing-Submissions-50' + }, + { + name : 'One Hundred Passing Submissions', + active : false, + specificClass : 'Passing-Submissions-100' + }, + { + name : 'Two Hundred And Fifty Passing Submissions', + active : false, + specificClass : 'Passing-Submissions-250' + }, + { + name : 'Five Hundred Passing Submissions', + active : false, + specificClass : 'Passing-Submissions-500' + } + ] + }, + { + id : 11, + groupClass : 'Checkpoint-Prizes', + specificAchievements : [ + { + name : 'First Milestone Prize', + active : false, + specificClass : 'Checkpoint-Prizes-1' + }, + { + name : 'Fifty Milestone Prizes', + active : false, + specificClass : 'Checkpoint-Prizes-50' + }, + { + name : 'One Hundred Milestone Prizes', + active : false, + specificClass : 'Checkpoint-Prizes-100' + }, + { + name : 'Two Hundred And Fifty Milestone Prizes', + active : false, + specificClass : 'Checkpoint-Prizes-250' + }, + { + name : 'Five Hundred Milestone Prizes', + active : false, + specificClass : 'Checkpoint-Prizes-500' + } + ] + }, + { + id : 16, + groupClass : 'Winning-Placements', + specificAchievements : [ + { + name : 'First Placement', + active : false, + specificClass : 'Winning-Placements-1' + }, + { + name : 'Twenty Five Placements', + active : false, + specificClass : 'Winning-Placements-25' + }, + { + name : 'Fifty Placements', + active : false, + specificClass : 'Winning-Placements-50' + }, + { + name : 'One hundred Placements', + active : false, + specificClass : 'Winning-Placements-100' + }, + { + name : 'Two Hundred And Fifty Placements', + active : false, + specificClass : 'Winning-Placements-250' + } + ] + }, + { + id : 21, + groupClass : 'First-Place-Wins', + specificAchievements : [ + { + name : 'First Win', + active : false, + specificClass : 'First-Place-Wins-1' + }, + { + name : 'Twenty Five First Placement Win', + active : false, + specificClass : 'First-Place-Wins-25' + }, + { + name : 'Fifty First Placement Win', + active : false, + specificClass : 'First-Place-Wins-50' + }, + { + name : 'One Hundred First Placement Win', + active : false, + specificClass : 'First-Place-Wins-100' + }, + { + name : 'Two Hundred And Fifty First Placement Win', + active : false, + specificClass : 'First-Place-Wins-250' + } + ] + }, + { + id : 0, + groupClass : 'HP-Badges-Level-1', + specificAchievements : [ + { + name : 'Getting Started', + active : false, + specificClass : 'Getting-Started' + }, + { + name : 'Novice', + active : false, + specificClass : 'Novice' + }, + { + name : 'Journeyman', + active : false, + specificClass : 'Journeyman' + }, + { + name : 'Expert', + active : false, + specificClass : 'Expert' + } + ] + }, + { + id : 0, + groupClass : 'HP-Badges-Level-2', + specificAchievements : [ + { + name : 'Master', + active : false, + specificClass : 'Master' + }, + { + name : 'Grand Master', + active : false, + specificClass : 'Grand-Master' + }, + { + name : 'Paragon', + active : false, + specificClass : 'Paragon' + }, + { + name : 'Grand Paragon', + active : false, + specificClass : 'Grand-Paragon' + }, + { + name : 'Social Evangelist', + active : false, + specificClass : 'Social-Evangelist' + } + ] + } + ] + + factory.singleAchievements = + [ + { + id : 121, + name : 'Marathon Match Winner', + groupClass : 'Marathon-Match-Winner', + active : false + }, + { + id : 122, + name : 'Algorithm Target', + groupClass : 'Algorithm-Target', + active : false + }, + { + id : 119, + name : 'SRM Winner Div 1', + groupClass : 'SRM-Winner-Div-1', + active : false + }, + { + id : 120, + name : 'SRM Winner Div 2', + groupClass : 'SRM-Winner-Div-2', + active : false + }, + { + id : 127, + name : 'Solved Hard Div2 Problem in SRM', + groupClass : 'Solved-Hard-Div2-Problem-in-SRM', + active : false + }, + { + id : 126, + name : 'Solved Hard Div1 Problem in SRM', + groupClass : 'Solved-Hard-Div1-Problem-in-SRM', + active : false + }, + { + id : 51, + name : 'Digital Run Winner', + groupClass : 'Digital-Run-Winner', + active : false + }, + { + id : 52, + name : 'Digital Run Top Five', + groupClass : 'Digital-Run-Top-5', + active : false + }, + { + id : 1, + name : 'Two Hundred Successful Challenges', + groupClass : 'Successful-Challenges-200', + active : false + }, + { + id : 129, + name : 'CoECI Client Badge', + groupClass : 'CoECI-Client-Badge', + active : false + }, + { + id : 0, + name : 'TopCoder Reviewer', + groupClass : 'TopCoder-Reviewer', + active : false + }, + { + id : 1000, + name : 'Studio Reviewer', + groupClass : 'Studio-Reviewer', + active : false + }, + { + id : 1000, + name : 'Studio Cup Top Five', + groupClass : 'Studio-Cup-Top-5', + active : false + }, + { + id : 1001, + name : 'Studio Cup Winner', + groupClass : 'Studio-Cup-Winner', + active : false + }, + { + id : 1002, + name : 'Studio Spec Reviewer', + groupClass : 'Studio-Spec-Reviewer', + active : false + }, + { + id : 1003, + name : 'Studio Screener', + groupClass : 'Studio-Screener', + active : false + }, + { + id : 1003, + name : 'Studio Spirit', + groupClass : 'Studio-Spirit', + active : false + }, + { + id : 1004, + name : 'Studio Mentor', + groupClass : 'Studio-Mentor', + active : false + }, + { + id : 1005, + name : 'Member of the Month', + groupClass : 'Member-of-the-Month', + active : false + }, + { + id : 1006, + name : 'Designer of the Month', + groupClass : 'Member-of-the-Month', + active : false + }, + { + id: 1007, + name: 'Crowd for Good', + groupClass: 'Crowd-for-Good', + active: false + }, + { + id: 1008, + name: 'Predix Community', + groupClass: 'Predix-Community', + active: false + }, + { + id: 1009, + name: 'iOS Community', + groupClass: 'iOS-Community', + active: false + }, + { + id: 1010, + name: 'SRM Engagement Honor', + groupClass: 'SRM-Engagement-Honor-Badge', + active: false + } + ] + } + + } + + +})() diff --git a/assets/css/directives/badge-tooltip.scss b/assets/css/directives/badge-tooltip.scss index dcbd83b98..08ceefc36 100644 --- a/assets/css/directives/badge-tooltip.scss +++ b/assets/css/directives/badge-tooltip.scss @@ -678,3 +678,7 @@ span.subBadge.selected { background: url(../../images/tt-arrow.png) no-repeat; background-position: 0 0; } + +.SRM-Engagement-Honor-Badge { + background-position: -146px -671px; +} \ No newline at end of file diff --git a/assets/css/directives/page-state-header.directive.scss b/assets/css/directives/page-state-header.directive.scss index 73c268774..1c7f06ca0 100644 --- a/assets/css/directives/page-state-header.directive.scss +++ b/assets/css/directives/page-state-header.directive.scss @@ -3,7 +3,8 @@ .page-state-header { background-color: $gray-lightest; padding: 15px; - border-bottom: 1px solid $gray-light; + border-bottom: 1px solid #D1D3D4; + border-top: 1px solid #D1D3D4; header { display: flex; @@ -22,67 +23,67 @@ .info { display: flex; flex-direction: row; - .pic { - img.profile-circle { - border-radius: 50%; - display: inline; - width: 60px; + + .item { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + + position: relative; + margin-left: 40px; + margin-right: 20px; + + font-family: 'Sofia Pro', Arial, Helvetica, sans-serif; + font-weight: 400; + + &:not(:first-child):before { + content: ''; + display: block; + position: absolute; + top: -5px; + left: -30px; + width: 1px; height: 60px; + -ms-transform: translateX(0) translateY(2px) rotate(30deg); + -webkit-transform: translateX(0) translateY(2px) rotate(30deg); + transform: translateX(0) translateY(2px) rotate(30deg); + background-color: #D1D3D4; } - } - } - .user-metrics { - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: center; - margin-bottom: 12px; - margin-left: 15px; - @media only screen and (min-width: 600px) { - margin-bottom: 0; - } + .value { + font-size: 24px; + margin-bottom: 15px; + } + + .title { + color: #A3A3AE; + font-size: 12px; + text-transform: uppercase; + } - .handle { - @include sofia-pro-medium; - font-size: 24px; - line-height: 29px; } - .money-earned { + .badgeItem { display: flex; - flex-direction: row; - align-items: center; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; - .number { - @include sofia-pro-bold; - font-size: 18px; - line-height: 23px; - color: $gray-darkest; - } + position: relative; + margin-left: 40px; + margin-right: 20px; + - p:not(.number) { - @include sofia-pro-regular; - font-size: 10px; - line-height: 13px; - text-transform: lowercase; - margin-left: 5px; - color: $accent-gray; - @media only screen and (min-width: 600px) { - font-size: 12px; - line-height: 14px; - } - } - } + font-family: 'Sofia Pro', Arial, Helvetica, sans-serif; + font-weight: 400; - .back-link { - @include sofia-pro-medium; - font-size: 12px; - line-height: 14px; - a { - color: $accent-gray; - } + .value { + font-size: 24px; + margin-bottom: 15px; + } } + } } } @@ -90,17 +91,20 @@ @media (min-width: 768px) { .page-state-header { - padding: 30px 60px; + padding: 30px 30px; header { flex-direction: row; align-items: center; justify-content: space-between; + max-width: 1300px; + margin: auto; .page-info { - order: 2; + order: 1; display: flex; flex-direction: row; + margin-left: 20px; h1 { font-size: 36px; line-height: 43px; diff --git a/assets/css/my-dashboard/header-dashboard.scss b/assets/css/my-dashboard/header-dashboard.scss index b9ebb9c4b..90112f6b4 100644 --- a/assets/css/my-dashboard/header-dashboard.scss +++ b/assets/css/my-dashboard/header-dashboard.scss @@ -2,7 +2,8 @@ .header-dashboard { // TODO: Use styleguide class - max-width: 1242px; - margin-left: auto; - margin-right: auto; + margin-left: -10px; + margin-right: -10px; + margin-top: -10px; + margin-bottom: 10px; } diff --git a/assets/images/badge.grid.large.png b/assets/images/badge.grid.large.png index b7c73ef24..66e446972 100644 Binary files a/assets/images/badge.grid.large.png and b/assets/images/badge.grid.large.png differ diff --git a/package-lock.json b/package-lock.json index 392177a00..44daf5a86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,11 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.0.2.tgz", "integrity": "sha512-vVdCha0AMQRMmE26AySLZG+R6qgZ8oNl4Qa2GxryM15rqY4zWKHl2hHLbfEXfaIxzdeDOmyX4O5p7gU/wT0jJw==" }, + "Base64": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.1.4.tgz", + "integrity": "sha1-6fbGvvVn/WNepBYqsU3TKedKpt4=" + }, "abbrev": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", @@ -1621,11 +1626,6 @@ "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.0.tgz", "integrity": "sha1-MeflYNyEbJ9EwaUx32UU2jVHQVc=" }, - "Base64": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.1.4.tgz", - "integrity": "sha1-6fbGvvVn/WNepBYqsU3TKedKpt4=" - }, "base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", @@ -9523,11 +9523,6 @@ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -9538,6 +9533,11 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/package.json b/package.json index b31a3a084..c55c5051b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Topcoder pages including login, registration, settings, dashboard, profile.", "scripts": { "build": "webpack --bail --progress --build --tc", - "start": "webpack-dev-server --history-api-fallback --host 0.0.0.0 --dev --tc --inline --progress --port 3000", + "start": "webpack-dev-server --history-api-fallback --host local.topcoder-dev.com --dev --tc --inline --progress --port 3000", "start-prod": "webpack-dev-server --history-api-fallback --host local.topcoder.com --prod --tc --inline --progress --port 80", "lint": "eslint .", "test": "karma start --tc --test"