diff --git a/app/account/logout/logout.spec.js b/app/account/logout/logout.spec.js index 8926430c1..da1f544b0 100644 --- a/app/account/logout/logout.spec.js +++ b/app/account/logout/logout.spec.js @@ -4,6 +4,11 @@ import angular from 'angular' describe('Logout Controller', function() { var controller var fakeWindow = { + // Without the `angular` field our fake window will crush + // `angular-mocks@1.6.2` and higher! + angular: { + callbacks: {} + }, location: { href: '' } @@ -15,14 +20,11 @@ describe('Logout Controller', function() { angular.mock.module('tc.account', function($provide) { $provide.value('$window', fakeWindow) }) - bard.inject(this, '$controller', 'TcAuthService', '$window', '$q', 'CONSTANTS') - bard.mockService(TcAuthService, { logout: $q.when({}), _default: $q.when({}) }) - controller = $controller('LogoutController') }) diff --git a/app/directives/challenge-tile/challenge-tile.jade b/app/directives/challenge-tile/challenge-tile.jade index 4660e4dfb..092f8e700 100644 --- a/app/directives/challenge-tile/challenge-tile.jade +++ b/app/directives/challenge-tile/challenge-tile.jade @@ -12,8 +12,8 @@ .challenge-details p.currentPhase {{challenge.userCurrentPhase}} - .challenge-calendar(ng-show="challenge.userCurrentPhaseEndTime") - p.ends-in Ends In + .challenge-calendar(ng-show="challenge.userCurrentPhaseEndTime", ng-class="{'challenge-late' : challenge.isLate}") + p.ends-in {{challenge.isLate ? 'Late for' : 'Ends In'}} p.time-remaining {{challenge.userCurrentPhaseEndTime[0]}} p.unit-of-time {{challenge.userCurrentPhaseEndTime[1]}} @@ -88,7 +88,7 @@ p.roles(ng-hide="challenge.track === 'DATA_SCIENCE'") #[span Role: ] #[span {{challenge.userDetails.roles | listRoles}}] .challenge-details - .challenge-info + .challenge-info(ng-class="{'challenge-late' : challenge.isLate}") p.currentPhase {{challenge.userCurrentPhase}} p.ends-in(ng-show="challenge.userCurrentPhaseEndTime") Ends: {{challenge.userCurrentPhaseEndTime[2] | localTime}} diff --git a/app/directives/tc-endless-paginator/tc-endless-paginator.jade b/app/directives/tc-endless-paginator/tc-endless-paginator.jade index ad76510d8..d735bf64b 100644 --- a/app/directives/tc-endless-paginator/tc-endless-paginator.jade +++ b/app/directives/tc-endless-paginator/tc-endless-paginator.jade @@ -1,3 +1,3 @@ div.paginator tc-section(state="state") - button.tc-btn.tc-btn-s(ng-show="pageParams.totalCount > pageParams.currentCount", ng-click="loadMore()") Load More + button.tc-btn.tc-btn-s(ng-show="pageParams.totalCount > pageParams.currentCount && firstLoadMore", ng-click="loadMore()") Load More diff --git a/app/directives/tc-section/tc-section.jade b/app/directives/tc-section/tc-section.jade index 76f9f2d85..7c57379e3 100644 --- a/app/directives/tc-section/tc-section.jade +++ b/app/directives/tc-section/tc-section.jade @@ -1,5 +1,5 @@ section(ng-switch="state") - .section-loading(ng-switch-when="loading") + .section-loading(ng-transclude, ng-switch-when="loading") .section-error(ng-switch-when="error") p {{errMsg}} diff --git a/app/layout/footer/footer.jade b/app/layout/footer/footer.jade index af8a7e04d..9da14e773 100644 --- a/app/layout/footer/footer.jade +++ b/app/layout/footer/footer.jade @@ -1,7 +1,6 @@ footer.bottom-footer // Footer links nav.menu-item - .menu-item-header.show-small OTHERS ul.submenu li.submenu-item #[a.menu-link(ng-href="https://www.{{domain}}/sitemap") SITE MAP] diff --git a/app/my-challenges/my-challenges.controller.js b/app/my-challenges/my-challenges.controller.js index d8623372c..41f6f5ad1 100644 --- a/app/my-challenges/my-challenges.controller.js +++ b/app/my-challenges/my-challenges.controller.js @@ -20,6 +20,7 @@ import _ from 'lodash' vm.loadMore = loadMore vm.getChallenges = getChallenges vm.totalCount = 0 + vm.firstLoadMore = true // this will help to keep track of pagination across individual api calls var counts = { devDesign: {total: 0, current: 0}, @@ -99,7 +100,7 @@ import _ from 'lodash' function getDevDesignChallenges(offset) { var params = { - limit: 12, + limit: CONSTANTS.CHALLENGES_LOADING_CHUNK, offset: offset, orderBy: vm.orderBy + ' desc', filter: 'status=' + vm.statusFilter @@ -125,7 +126,7 @@ import _ from 'lodash' _filter = 'status=past&isRatedForMM=true' } var params = { - limit: 12, + limit: CONSTANTS.CHALLENGES_LOADING_CHUNK, offset: offset, orderBy: vm.statusFilter === 'active' ? 'startDate' : 'endDate desc', filter: _filter @@ -142,12 +143,14 @@ import _ from 'lodash' } function loadMore() { - currentOffset+=12 - vm.getChallenges(currentOffset, false) + if (vm.loading === CONSTANTS.STATE_READY) { + currentOffset += CONSTANTS.CHALLENGES_LOADING_CHUNK + vm.getChallenges(currentOffset, false) + } } window.onscroll = function() { - if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - CONSTANTS.INFINITE_SCROLL_OFFSET)) { if (vm.totalCount > vm.myChallenges.length) { vm.loadMore() } diff --git a/app/my-challenges/my-challenges.jade b/app/my-challenges/my-challenges.jade index 644a84e4b..723c9c8ca 100644 --- a/app/my-challenges/my-challenges.jade +++ b/app/my-challenges/my-challenges.jade @@ -30,3 +30,5 @@ challenge-tile( ng-repeat="challenge in vm.myChallenges | orderBy:vm.orderBy:true", challenge="challenge", view="vm.view", ng-class="vm.view + '-view'") + + tc-section.load-more-section(state="vm.loading") diff --git a/app/profile/badges/badges.controller.js b/app/profile/badges/badges.controller.js index 4359ac019..f99750f43 100644 --- a/app/profile/badges/badges.controller.js +++ b/app/profile/badges/badges.controller.js @@ -661,6 +661,12 @@ import moment from 'moment-timezone' name: 'Predix Community', groupClass: 'Predix-Community', active: false + }, + { + id: 1009, + name: 'iOS Community', + groupClass: 'iOS-Community', + active: false } ] } diff --git a/app/profile/subtrack/subtrack.controller.js b/app/profile/subtrack/subtrack.controller.js index 8e4b5b131..14b1ce99b 100644 --- a/app/profile/subtrack/subtrack.controller.js +++ b/app/profile/subtrack/subtrack.controller.js @@ -26,9 +26,8 @@ import _ from 'lodash' vm.showNav = showNav vm.back = back vm.subTrackStats = [] - + vm.loadMore = loadMore vm.pageName = vm.subTrack - vm.tabs = ['statistics'] if (vm.track !== 'COPILOT') { @@ -41,7 +40,7 @@ import _ from 'lodash' // paging params, these are updated by tc-pager vm.pageParams = { currentOffset : 0, - limit: 16, + limit: CONSTANTS.CHALLENGES_LOADING_CHUNK, currentCount: 0, totalCount: 0, // counter used to indicate page change @@ -156,6 +155,21 @@ import _ from 'lodash' $window.history.back() } + function loadMore() { + if (vm.status.challenges === CONSTANTS.STATE_READY) { + vm.pageParams.currentOffset += CONSTANTS.CHALLENGES_LOADING_CHUNK + _getChallenges() + } + } + + window.onscroll = function() { + if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - CONSTANTS.INFINITE_SCROLL_OFFSET)) { + if (vm.pageParams.totalCount > vm.challenges.length) { + vm.loadMore() + } + } + } + function _getChallenges() { vm.status.challenges = CONSTANTS.STATE_LOADING var params = { diff --git a/app/services/blog.service.js b/app/services/blog.service.js index 3047dcceb..fe632e3d6 100644 --- a/app/services/blog.service.js +++ b/app/services/blog.service.js @@ -19,7 +19,7 @@ import X2JS from 'xml2js' // fetch blog rss feed $http.get(CONSTANTS.BLOG_LOCATION) - .success(function(data) { + .then(function(data) { // parse the blog rss feed using x2js var parseString = X2JS.parseString parseString(data.trim(), function (err, res) { @@ -38,8 +38,7 @@ import X2JS from 'xml2js' deferred.resolve(result) }) - }) - .error(function(error) { + }, function(error) { deferred.reject(error) }) diff --git a/app/services/challenge.service.js b/app/services/challenge.service.js index c71b4978e..a9ecd0492 100644 --- a/app/services/challenge.service.js +++ b/app/services/challenge.service.js @@ -119,6 +119,7 @@ import moment from 'moment' // Add actual time ['2', 'months', actual date] timeAndUnit.push(fullTime) challenge.userCurrentPhaseEndTime = timeAndUnit + challenge.isLate = moment().diff(fullTime) > 0 // If > 0 then the challenge has 'Late Deliverables' or } }) } diff --git a/app/services/helpers.service.spec.js b/app/services/helpers.service.spec.js index 9e1757f6f..2508bfe9f 100644 --- a/app/services/helpers.service.spec.js +++ b/app/services/helpers.service.spec.js @@ -5,6 +5,11 @@ const mockData = require('../../tests/test-helpers/mock-data') describe('Helper Service', function() { var fakeWindow = { + // Without the `angular` field our fake window will crush + // `angular-mocks@1.6.2` and higher! + angular: { + callbacks: {} + }, location: { href: '/' }, diff --git a/app/services/jwtInterceptor.service.spec.js b/app/services/jwtInterceptor.service.spec.js index 8715e1896..ec11b7461 100644 --- a/app/services/jwtInterceptor.service.spec.js +++ b/app/services/jwtInterceptor.service.spec.js @@ -33,6 +33,11 @@ describe('JWT Interceptor Service', function() { }) }, fakeWindow = { + // Without the `angular` field our fake window will crush + // `angular-mocks@1.6.2` and higher! + angular: { + callbacks: {} + }, location: '' } diff --git a/app/topcoder.constants.js b/app/topcoder.constants.js index 708842a25..8fd2fd272 100644 --- a/app/topcoder.constants.js +++ b/app/topcoder.constants.js @@ -43,5 +43,7 @@ angular.module('CONSTANTS', []).constant('CONSTANTS', { 'REGISTERED' : 'REGISTERED', 'SUBMISSION_TYPE_CONTEST': 'Contest Submission', 'STATUS_ACTIVE' : 'Active', - 'STATUS_COMPLETED_WITHOUT_WIN' : 'Completed Without Win' + 'STATUS_COMPLETED_WITHOUT_WIN' : 'Completed Without Win', + 'CHALLENGES_LOADING_CHUNK' : 36, + 'INFINITE_SCROLL_OFFSET' : '400' // footer is 300px and challenge tile is 400px }) diff --git a/assets/css/directives/badge-tooltip.scss b/assets/css/directives/badge-tooltip.scss index 156b73aea..fbcf074cf 100644 --- a/assets/css/directives/badge-tooltip.scss +++ b/assets/css/directives/badge-tooltip.scss @@ -440,6 +440,9 @@ .Predix-Community { background-position: -50px -672px; } +.iOS-Community { + background-position: -95px -672px; +} .Wireframe { width: 31px; background-position: 0px -1009px !important; diff --git a/assets/css/directives/challenge-tile.scss b/assets/css/directives/challenge-tile.scss index 163886747..ef8b13dc8 100644 --- a/assets/css/directives/challenge-tile.scss +++ b/assets/css/directives/challenge-tile.scss @@ -222,6 +222,12 @@ challenge-tile .challenge.tile-view { text-transform: lowercase; color: #7F7F7F; } + + &.challenge-late { + .ends-in, .time-remaining, .unit-of-time { + color: #ee6666; + } + } } .stalled-challenge { @@ -462,6 +468,12 @@ challenge-tile .challenge.list-view { font-size: 14px; color: #A3A3AE; } + + &.challenge-late { + .ends-in, .time-remaining, .unit-of-time { + color: #ee6666; + } + } } .marathon-score { diff --git a/assets/css/directives/tc-section.scss b/assets/css/directives/tc-section.scss index c53ab8adb..10d784d6c 100644 --- a/assets/css/directives/tc-section.scss +++ b/assets/css/directives/tc-section.scss @@ -5,6 +5,7 @@ .section-loading { width: 100%; + min-width: 50px; min-height: 100px; background: url(../../images/ripple.gif) no-repeat center center; } diff --git a/assets/css/layout/footer.scss b/assets/css/layout/footer.scss index 8d0906753..dcbcb09fb 100644 --- a/assets/css/layout/footer.scss +++ b/assets/css/layout/footer.scss @@ -1,17 +1,31 @@ @import 'topcoder/tc-includes'; +footer { + font-family: "Merriweather Sans","Helvetica Neue",Helvetica,Arial,sans-serif; + font-weight: 400; +} + .bottom-footer { background-color: $gray-darkest; padding: 1px 20px 30px 20px; } +.bottom-footer .menu-item .menu-link { + color: $tc-white; + font-size: 16px; +} + +.bottom-footer .menu-item .menu-link:hover { + color: $primary; +} + .social-links { font-size: 13px; line-height: 1.2em; text-align: center; font-weight: normal; margin: 35px 0; - color: #fff; + color: $tc-white; a { display: inline-block; @@ -23,64 +37,83 @@ margin-left: 30px; } } + + .fb-link { + background-image: url(../../images/ico-facebook_desktop.svg); + width: 27px; + height: 27px; + } + + .twitter-link { + background-image: url(../../images/ico-twitter_desktop.svg); + width: 28px; + height: 24px; + } + + .linkedin-link { + background-image: url(../../images/ico-linkedin_desktop.svg); + width: 27px; + height: 27px; + } + + .google-link { + background-image: url(../../images/ico-google_desktop.svg); + width: 27px; + height: 27px; + } } .copyright-notice { text-align: center; font-size: 12px; line-height: 14px; - color: #656565; + color: $tc-white; } @media only screen and (max-width : 1024px) { // removed fold-pusher from the rule to remove white space - // .bottom-footer, .fold-pusher { - .bottom-footer { - height: 200px; + .bottom-footer, .fold-pusher { + // .bottom-footer { + height: auto; } .bottom-footer .menu-item { - display: none; - margin-top: 10px; - } - - .menu-visible .bottom-footer .menu-item { display: block; } + .bottom-footer { + padding-top: 36px; + } .social-links { + margin-top: 0; + margin-bottom: 6px; + .fb-link { - background-image: url(../../images/ico-facebook.svg); width: 27px; height: 27px; } .twitter-link { - background-image: url(../../images/ico-twitter.svg); width: 28px; height: 24px; } .linkedin-link { - background-image: url(../../images/ico-linkedin.svg); width: 27px; height: 27px; } .google-link { - background-image: url(../../images/ico-google.svg); width: 27px; height: 27px; } } .bottom-footer nav { - position: absolute; - top: 1047px; - left: 0; - width: 100%; - padding: 20px; - background-color: $gray-darkest; + position: relative;; + top: auto; + left: auto; + text-align: center; ul a { color: $white; @@ -90,9 +123,9 @@ @media only screen and (min-width : 1025px) { // removed fold-pusher from the rule to remove white space - // .bottom-footer, .fold-pusher { - .bottom-footer { - height: 270px; + .bottom-footer, .fold-pusher { + // .bottom-footer { + height: 200px; } .bottom-footer { padding-top: 40px; @@ -106,25 +139,19 @@ font-weight: normal; .menu-link { - color: #fff; - font-size: 16px; line-height: 21px; } - .menu-link:hover { - color: #0096ff; - } } } .copyright-notice { font-size: 15px; - color: #fff; + color: $tc-white; } .account-footer { .copyright-notice { font-size: 12px; - color: #656565; } } @@ -136,21 +163,5 @@ height: 26px; margin-top: 13px; } - - .fb-link { - background-image: url(../../images/ico-facebook_desktop.svg); - } - - .twitter-link { - background-image: url(../../images/ico-twitter_desktop.svg); - } - - .linkedin-link { - background-image: url(../../images/ico-linkedin_desktop.svg); - } - - .google-link { - background-image: url(../../images/ico-google_desktop.svg); - } } } diff --git a/assets/css/profile/badges.scss b/assets/css/profile/badges.scss index 00e180538..271ed3ef3 100644 --- a/assets/css/profile/badges.scss +++ b/assets/css/profile/badges.scss @@ -40,6 +40,7 @@ background: #fbfbfb; border: 1px solid #f0f0f0; width: 30%; + min-width: 300px; display: flex; flex-direction: column; justify-content: center; @@ -60,23 +61,23 @@ } .ngdialog-close { display: block; - } + } } - + .ngdialog-close { display: none; } - + .ngdialog-close.close-outside { display: block; height: 100%; width: 100%; cursor: default; } - + .ngdialog-close.close-outside:before { display: none; - } + } } } diff --git a/assets/images/badge.grid.large.png b/assets/images/badge.grid.large.png index 7e3a747d5..b7c73ef24 100644 Binary files a/assets/images/badge.grid.large.png and b/assets/images/badge.grid.large.png differ diff --git a/assets/scripts/kissmetrics.analytics.js b/assets/scripts/kissmetrics.analytics.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/assets/scripts/munchkin.analytics.js b/assets/scripts/munchkin.analytics.js deleted file mode 100644 index 8b60ec182..000000000 --- a/assets/scripts/munchkin.analytics.js +++ /dev/null @@ -1,22 +0,0 @@ -// tracking code for Marketo -(function() { - var didInit = false - function initMunchkin() { - if(didInit === false) { - didInit = true - /*eslint no-undef:0 */ - Munchkin.init('921-UOU-112', {'wsInfo':'jFRS'}) - } - } - var s = document.createElement('script') - s.type = 'text/javascript' - s.async = true - s.src = '//munchkin.marketo.net/munchkin.js' - s.onreadystatechange = function() { - if (this.readyState == 'complete' || this.readyState == 'loaded') { - initMunchkin() - } - } - s.onload = initMunchkin - document.getElementsByTagName('head')[0].appendChild(s) -})() diff --git a/package.json b/package.json index 1c9d60547..ca19358b7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "test": "karma start --tc --test" }, "devDependencies": { - "angular-mocks": "^1.4.9", + "angular-mocks": "^1.6.2", "appirio-tech-webpack-config": "^0.3.8", "babel-polyfill": "^6.7.2", "bardjs": "^0.1.8", @@ -51,12 +51,12 @@ "angular-sanitize": "^1.4.9", "angular-storage": "0.0.13", "angular-touch": "^1.4.9", - "angular-ui-router": "^0.2.16", + "angular-ui-router": "^0.4.2", "angularjs-toaster": "^1.0.0", "appirio-styles": "0.x.x", "appirio-tech-ng-iso-constants": "^1.0.6", "appirio-tech-ng-ui-components": "^2.1.2", - "appirio-tech-react-components": "appirio-tech/react-components.git#cl-styles-1", + "appirio-tech-react-components": "appirio-tech/react-components.git#challenge-listings", "auth0-angular": "^4.1.0", "auth0-js": "^6.8.0", "d3": "^3.5.14",