From ac611d61fb0fc816e7448ed5e18c41ddcf4df6e7 Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Thu, 23 Apr 2015 16:04:42 -0700 Subject: [PATCH 1/8] minor copy fix --- seed_data/coursewares.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 5d0f1a59ab..15ab4cf9e2 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -979,7 +979,7 @@ }, { "_id": "bd7158d8c443eddfaeb5bdee", - "name": "Basejump: Build Pintrest Clone", + "name": "Basejump: Build a Pintrest Clone", "difficulty": 2.05, "challengeSeed": "123488494", "description": [ From bf723b522bc45a451780dc6944e18cc3ee6d3575 Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Thu, 23 Apr 2015 23:46:58 -0700 Subject: [PATCH 2/8] start making ux changes --- app.js | 4 +- controllers/challengeMap.js | 38 +++++++++++++++---- controllers/challenges.js | 59 ------------------------------ public/js/main.js | 13 +------ views/challengeMap/show.jade | 39 +++++++++++++++++--- views/challenges/show.jade | 50 ------------------------- views/partials/footer.jade | 3 -- views/partials/navbar-narrow.jade | 4 +- views/resources/learn-to-code.jade | 18 --------- 9 files changed, 68 insertions(+), 160 deletions(-) delete mode 100644 controllers/challenges.js delete mode 100644 views/challenges/show.jade diff --git a/app.js b/app.js index bd36ff727c..5f730fe264 100755 --- a/app.js +++ b/app.js @@ -299,9 +299,9 @@ app.get('/nodeschool-challenges', function(req, res) { app.get('/news', function(req, res) { res.redirect(301, '/stories/hot'); }); -app.get('/learn-to-code', resourcesController.about); +app.get('/learn-to-code', challengeMapController.challengeMap); app.get('/about', function(req, res) { - res.redirect(301, '/learn-to-code'); + res.redirect(301, '/map'); }); app.get('/signin', userController.getSignin); diff --git a/controllers/challengeMap.js b/controllers/challengeMap.js index b858bf7385..c6418b41c7 100644 --- a/controllers/challengeMap.js +++ b/controllers/challengeMap.js @@ -52,14 +52,36 @@ module.exports = { if (challenge.challengeType === 4) { return challenge } }); - res.render('challengeMap/show', { - title: "A map of all Free Code Camp's Challenges", - bonfires: bonfireList, - waypoints: waypoints, - ziplines: ziplines, - basejumps: basejumps, - completedBonfireList: completedBonfireList, - completedCoursewareList: completedCoursewareList + if (!req.user.profile.picture || req.user.profile.picture === "https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png") { + req.user.profile.picture = "https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png"; + req.user.save(); + } + + function numberWithCommas(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + + var date1 = new Date("10/15/2014"); + var date2 = new Date(); + var timeDiff = Math.abs(date2.getTime() - date1.getTime()); + var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24)); + + User.count({}, function (err, camperCount) { + if (err) { + debug('User err: ', err); + return next(err); + } + res.render('challengeMap/show', { + daysRunning: daysRunning, + camperCount: numberWithCommas(camperCount), + title: "A map of all Free Code Camp's Challenges", + bonfires: bonfireList, + waypoints: waypoints, + ziplines: ziplines, + basejumps: basejumps, + completedBonfireList: completedBonfireList, + completedCoursewareList: completedCoursewareList + }); }); } }; diff --git a/controllers/challenges.js b/controllers/challenges.js deleted file mode 100644 index 463edda920..0000000000 --- a/controllers/challenges.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * GET / - * Challenges. - */ -var _ = require('lodash'), - debug = require('debug')('freecc:cntr:challenges'), - Challenge = require('./../models/Challenge'), - resources = require('./resources'); - -var highestChallengeNumber = 53; - - -exports.returnNextChallenge = function(req, res) { - if (req.user) { - ch = req.user.challengesHash; - if (req.user.challengesHash[0] > 0) { - var max = Object.keys(ch).reduce(function(max, key) { - return (max === undefined || ch[key] > ch[max]) ? +key : max; - }); - nextChallenge = max + 1; - res.redirect('challenges/' + nextChallenge); - } else { - res.redirect('challenges/0'); - } - } else { - return res.redirect('../challenges/0'); - } -}; - -exports.returnChallenge = function(req, res, next) { - var challengeNumber = parseInt(req.params.challengeNumber) || 0; - - if (challengeNumber > highestChallengeNumber) { - req.flash('errors', { - msg: "It looks like you've either completed all the challenges we have available or requested a challenge we don't have." - }); - return res.redirect('../challenges/0'); - } - Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) { - if (err) { - debug('Challenge err: ', err); - return next(err); - } - res.render('challenges/show', { - title: 'Challenge: ' + c[challengeNumber].name, - name: c[challengeNumber].name, - video: c[challengeNumber].video, - time: c[challengeNumber].time, - steps: c[challengeNumber].steps, - number: challengeNumber, - cc: req.user ? req.user.challengesHash : undefined, - points: req.user ? req.user.points : undefined, - verb: resources.randomVerb(), - phrase: resources.randomPhrase(), - compliment: resources.randomCompliment(), - challenges: c - }); - }); -}; diff --git a/public/js/main.js b/public/js/main.js index 59905c18e3..ee6c9e1cb8 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -4,13 +4,6 @@ $(document).ready(function() { ga('send', 'event', 'Challenge', 'load', challengeName); } - // When introducing a new announcement, change the localStorage attribute - // and the HTML located in the footer - if (!localStorage || !localStorage.nodeSchoolAnnouncement) { - $('#announcementModal').modal('show'); - localStorage.fccShowAnnouncement = "true"; - } - var CSRF_HEADER = 'X-CSRF-Token'; var setCSRFToken = function(securityToken) { @@ -204,10 +197,6 @@ $(document).ready(function() { } }); - $('.all-challenges').on('click', function() { - $('#show-all-dialog').modal('show'); - }); - $('#showAllButton').on('click', function() { $('#show-all-dialog').modal('show'); }); @@ -217,7 +206,7 @@ $(document).ready(function() { window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1); }); -// Bonfire instructions functions + // Bonfire instructions functions $('#more-info').on('click', function() { ga('send', 'event', 'Challenge', 'more-info', challengeName); $('#brief-instructions').hide(); diff --git a/views/challengeMap/show.jade b/views/challengeMap/show.jade index 5c230072df..bd4a76ea7b 100644 --- a/views/challengeMap/show.jade +++ b/views/challengeMap/show.jade @@ -5,10 +5,19 @@ block content .panel-heading.text-center h1 Challenge Map .panel-body - .row - .col-xs-12.col-sm-12.col-md-10.col-md-offset-2 - h3 Complete all of these challenges from top to bottom. - h3 Then we'll assign you to your first nonprofit project. + .col-xs-12 + if (Math.random() > 0.99) + img.img-responsive.img-center(src='https://s3.amazonaws.com/freecodecamp/wide-social-banner-dino.png') + else + img.img-responsive.img-center(src='https://s3.amazonaws.com/freecodecamp/wide-social-banner.png') + .col-xs-12.col-md-8.col-md-offset-2 + h2.text-center + span.text-primary #{camperCount}   + | campers have joined our community + br + | since we launched   + span.text-primary #{daysRunning}   + | days ago. h2 span.fa.fa-flag |   Waypoints (200 hours of lessons) @@ -92,7 +101,7 @@ block content li a(href="/challenges/#{basejump.name}")= basejump.name h2 - span.ion-ios-heart   Nonprofit Projects (800 hours of real-world experience) + span.ion-ios-heart   Nonprofit Projects (800 hours of real-world experience)* h3.negative-15 ul .row @@ -101,3 +110,23 @@ block content .col-xs-12.col-sm-9.col-md-10 li a(href="/nonprofits/directory") Browse our nonprofit projects + p * Complete all Waypoints, Bonfires, Ziplines and Basejumps to be assigned your first nonprofit project + + //#announcementModal.modal(tabindex='-1') + // .modal-dialog + // .modal-content + // .modal-header.challenge-list-header We've updated our curriculum + // a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + // .modal-body + // h3.text-left We now have a 1,600 hour curriculum and tons of new challenges. Read more about it + // a(href='http://blog.freecodecamp.com', target='_blank') here + // | . + // a.btn.btn-lg.btn-info.btn-block(name='_csrf', value=_csrf, aria-hidden='true', href='http://blog.freecodecamp.com/', target='_blank') Take me to the blog post. + // a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Thanks for the heads-up! + //script. + // $(document).ready(function () { + // if (!localStorage || !localStorage.newCurriculum) { + // $('#announcementModal').modal('show'); + // localStorage.campWideMeeting = "true"; + // } + // }); diff --git a/views/challenges/show.jade b/views/challenges/show.jade deleted file mode 100644 index c2843bb107..0000000000 --- a/views/challenges/show.jade +++ /dev/null @@ -1,50 +0,0 @@ -extends ../layout -block content - .row - .col-sm-12.col-md-12.col-xs-12 - .panel.panel-primary - .panel-heading.text-center - h1 #{name} (takes #{time} minutes) - script. - var challengeName = null; - .panel.panel-body - .embed-responsive.embed-responsive-16by9 - iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') - .col-xs-12.col-sm-10.col-sm-offset-1.col-md-8.col-md-offset-2 - h3 Steps: - h4 - ol - for step in steps - li!= step - .btn.btn-primary.btn-big.btn-block.completed-challenge I've completed this challenge - .ten-pixel-break - .btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges - #complete-challenge-dialog.modal(tabindex='-1') - .modal-dialog.animated.zoomIn.fast-animation - .modal-content - .modal-header.challenge-list-header= compliment - a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - .modal-body - .text-center - .animated.zoomInDown.delay-half - span.completion-icon.ion-checkmark-circled.text-primary - - if (cc) - a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-challenge-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge - - if (points && points > 2) - a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank") - i.fa.fa-twitter   - = phrase - - else - a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress - - script. - $.ajax({ - url: 'https://api-ssl.bitly.com/v3/shorten?access_token=75e7931a19befaafcf108021b6d597e554b2c5c3&longUrl=http%3A%2F%2Ffreecodecamp.com%2Fchallenges%2F' + !{JSON.stringify(number)} + '&format=txt' - }) - .success( - function (data) { - console.log(data); - url = "https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Challenge:%20#{name}&url=" + data + "&hashtags=LearnToCode, JavaScript"; - $('.btn-twitter').attr('href', url); - } - ); diff --git a/views/partials/footer.jade b/views/partials/footer.jade index 3004dcbcf1..de503bde8f 100644 --- a/views/partials/footer.jade +++ b/views/partials/footer.jade @@ -4,7 +4,6 @@ a.ion-social-twitch-outline(href="/twitch")  Twitch  a.ion-social-github(href="http://github.com/freecodecamp", target='_blank')  Github   a.ion-social-twitter(href="http://twitter.com/freecodecamp", target='_blank')  Twitter   - a.ion-information-circled(href="/learn-to-code")  About   a.ion-locked(href="/privacy")  Privacy   .col-xs-12.visible-xs.visible-sm a.ion-speakerphone(href='http://blog.freecodecamp.com', target='_blank') @@ -15,7 +14,5 @@ span.sr-only Free Code Camp on GitHub a.ion-social-twitter(href="http://twitter.com/freecodecamp", target='_blank') span.sr-only Free Code Camp on Twitter - a.ion-information-circled(href="/learn-to-code") - span.sr-only About Free Code Camp a.ion-locked(href="/privacy") span.sr-only Free Code Camp's Privacy Policy diff --git a/views/partials/navbar-narrow.jade b/views/partials/navbar-narrow.jade index b8ff7267f9..8b13789179 100644 --- a/views/partials/navbar-narrow.jade +++ b/views/partials/navbar-narrow.jade @@ -1,3 +1 @@ -nav.navbar.navbar-default.navbar-fixed-top.nav-height - .container - include ./navbar \ No newline at end of file + diff --git a/views/resources/learn-to-code.jade b/views/resources/learn-to-code.jade index 9c87cf1a7a..59b9586ecc 100644 --- a/views/resources/learn-to-code.jade +++ b/views/resources/learn-to-code.jade @@ -63,21 +63,3 @@ block content .col-xs-12.github-and-twitter-button-text html. - //#announcementModal.modal(tabindex='-1') - // .modal-dialog - // .modal-content - // .modal-header.challenge-list-header Camp-wide Meeting on Saturday at Noon EST - // a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - // .modal-body - // h3.text-left We'll live-stream some of Free Code Camp's new features, and campers will show what they're building. Live Saturday, March 28 at Noon EST on our   - // a(href='http://twitch.tv/freecodecamp', target='_blank') Twitch.tv channel - // | . - // a.btn.btn-lg.btn-info.btn-block(name='_csrf', value=_csrf, aria-hidden='true', href='http://twitch.tv/freecodecamp', target='_blank') Take me to Twitch so I can follow Free Code Camp - // a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Thanks for the heads-up! - //script. - // $(document).ready(function () { - // if (!localStorage || !localStorage.campWideMeeting) { - // $('#announcementModal').modal('show'); - // localStorage.campWideMeeting = "true"; - // } - // }); From e5e47136ea8ef0fe4a3fa87c1f4bc8762830b16c Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 24 Apr 2015 01:31:59 -0700 Subject: [PATCH 3/8] make all navbar layouts wide style, redirect logo to challenge map, improve navbar collapse --- controllers/home.js | 2 +- public/css/main.less | 51 ++++++++++++++--- views/account/show.jade | 11 ++-- views/layout-wide.jade | 4 +- views/layout.jade | 2 +- views/partials/navbar-narrow.jade | 1 - views/partials/navbar-wide.jade | 2 - views/partials/navbar.jade | 94 ++++++++++++++++--------------- 8 files changed, 103 insertions(+), 64 deletions(-) delete mode 100644 views/partials/navbar-narrow.jade delete mode 100644 views/partials/navbar-wide.jade diff --git a/controllers/home.js b/controllers/home.js index 836ad9e62b..686cd2a80c 100644 --- a/controllers/home.js +++ b/controllers/home.js @@ -5,7 +5,7 @@ exports.index = function(req, res) { if (req.user) { - res.redirect('/challenges/') + res.redirect('/map') } else { res.render('home', { title: 'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits' diff --git a/public/css/main.less b/public/css/main.less index d6e905c8ea..cf93cebef7 100644 --- a/public/css/main.less +++ b/public/css/main.less @@ -273,11 +273,6 @@ ul { height: 30px; margin-top: -5px; } - @media (min-width: 767px) and (max-width: 890px) { - height: 30px; - margin-top: -5px; - } - } .navbar-right { @@ -790,10 +785,52 @@ iframe.iphone { transition: background .2s ease-in-out, border .2s ease-in-out; } +@media (max-width: 991px) { + .navbar-header { + float: none; + } + + .navbar-toggle { + display: block; + } + + .navbar-collapse.collapse { + display: none !important; + } + + .navbar-nav { + float: none !important; + margin: 7.5px -15px; + } + + .navbar-nav > li { + float: none; + } + + .navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + } + + .navbar-text { + float: none; + margin: 15px 0; + } + + /* since 3.1.0 */ + .navbar-collapse.collapse.in { + display: block !important; + } + + .collapsing { + overflow: hidden !important; + } +} + .hamburger { width: 80px; padding-left: 0px; - padding-right: 0px; + padding-right: 8px; margin-left: 0px; margin-right: 2px; text-align:left; @@ -804,7 +841,7 @@ iframe.iphone { line-height: 0.75em; margin-top: 10px; font-size: 16px; - margin-left: -5px; + margin-left: -8px; } .tight-h3 { diff --git a/views/account/show.jade b/views/account/show.jade index 8dd1314227..deb8168b4f 100644 --- a/views/account/show.jade +++ b/views/account/show.jade @@ -8,10 +8,13 @@ block content h1 #{username}'s portfolio .panel-body if (user && user.profile.username === username) - .col-xs-12 - .text-center - a.btn.btn-big.btn-primary(href="/account") Update my portfolio page or manage my account - br + .row.text-center + .col-xs-12.col-sm-10.col-sm-offset-1 + a.btn.btn-big.btn-primary.btn-block(href="/account") Update my portfolio page or manage my account + .spacer + .col-xs-12.col-sm-10.col-sm-offset-1 + a.btn.btn-big.btn-success.btn-block(href="/signout") Sign out of Free Code Camp + .spacer .row .col-xs-12 .col-xs-12.col-sm-12.col-md-5 diff --git a/views/layout-wide.jade b/views/layout-wide.jade index a320f210a5..fe05524cb0 100644 --- a/views/layout-wide.jade +++ b/views/layout-wide.jade @@ -6,8 +6,8 @@ html(ng-app='profileValidation', lang='en') body.no-top-and-bottom-margins.full-screen-body-background include partials/css-cdns - include partials/navbar-wide + include partials/navbar include partials/flash block content include partials/footer - != js('application') \ No newline at end of file + != js('application') diff --git a/views/layout.jade b/views/layout.jade index e50689c0a7..48e11a3143 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -5,7 +5,7 @@ html(ng-app='profileValidation', lang='en') != css('main') body.top-and-bottom-margins include partials/css-cdns - include partials/navbar-narrow + include partials/navbar .container include partials/flash block content diff --git a/views/partials/navbar-narrow.jade b/views/partials/navbar-narrow.jade deleted file mode 100644 index 8b13789179..0000000000 --- a/views/partials/navbar-narrow.jade +++ /dev/null @@ -1 +0,0 @@ - diff --git a/views/partials/navbar-wide.jade b/views/partials/navbar-wide.jade deleted file mode 100644 index 96165a030d..0000000000 --- a/views/partials/navbar-wide.jade +++ /dev/null @@ -1,2 +0,0 @@ -nav.navbar.navbar-default.navbar-fixed-top.nav-height - include ./navbar \ No newline at end of file diff --git a/views/partials/navbar.jade b/views/partials/navbar.jade index f563f92c81..e409e3860a 100644 --- a/views/partials/navbar.jade +++ b/views/partials/navbar.jade @@ -1,54 +1,56 @@ -.navbar-header - button.hamburger.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse') - .col-xs-6 - span.hamburger-text Menu - .col-xs-6 - span.sr-only Toggle navigation - span.icon-bar - span.icon-bar - span.icon-bar - a.navbar-brand(href='/') - img.img-responsive.nav-logo(src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg.gz', alt='learn to code javascript at Free Code Camp logo') -.collapse.navbar-collapse - ul.nav.navbar-nav.navbar-right.hamburger-dropdown +nav.navbar.navbar-default.navbar-fixed-top.nav-height + .navbar-header + button.hamburger.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse') + .col-xs-6 + span.hamburger-text Menu + .col-xs-6 + span.sr-only Toggle navigation + span.icon-bar + span.icon-bar + span.icon-bar + a.navbar-brand(href='/') + img.img-responsive.nav-logo(src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg.gz', alt='learn to code javascript at Free Code Camp logo') + .collapse.navbar-collapse + ul.nav.navbar-nav.navbar-right.hamburger-dropdown - li - a(href='/map') Map - - if (user && user.sentSlackInvite) li - a(href='/chat', target='_blank') Chat - else + a(href='/challenges') Next Challenge li - a(href='/challenges/join-our-chat-room') Chat - li - a(href='/stories/hot') News - li - a(href='/field-guide') Field Guide - if !user - li       + a(href='/map') Map + if (user && user.sentSlackInvite) + li + a(href='/chat', target='_blank') Chat + else + li + a(href='/challenges/join-our-chat-room') Chat li - a.btn.signup-btn.signup-btn-nav(href='/login') Sign in - else + a(href='/stories/hot') News li - if (user.profile.username) - - a(href='/' + user.profile.username) [ #{user.progressTimestamps.length} ] - - else - a(href='/account') [ #{user.progressTimestamps.length} ] - .hidden-xs - if user.profile.picture + a(href='/field-guide') Field Guide + if !user + li       + li + a.btn.signup-btn.signup-btn-nav(href='/login') Sign in + else + li if (user.profile.username) - a(href='/' + user.profile.username) - img.profile-picture.float-right(src='#{user.profile.picture}') + + a(href='/' + user.profile.username) [ #{user.progressTimestamps.length} ] + else - a(href='/account') - img.profile-picture.float-right(src='#{user.profile.picture}') - else - if (user.profile.username) - a(href='/' + user.profile.username) - img.profile-picture.float-right(src='#{user.gravatar(60)}') + a(href='/account') [ #{user.progressTimestamps.length} ] + .hidden-xs.hidden-sm + if user.profile.picture + if (user.profile.username) + a(href='/' + user.profile.username) + img.profile-picture.float-right(src='#{user.profile.picture}') + else + a(href='/account') + img.profile-picture.float-right(src='#{user.profile.picture}') else - a(href='/account') - img.profile-picture.float-right(src='#{user.gravatar(60)}') + if (user.profile.username) + a(href='/' + user.profile.username) + img.profile-picture.float-right(src='#{user.gravatar(60)}') + else + a(href='/account') + img.profile-picture.float-right(src='#{user.gravatar(60)}') From bea77c580ec050c5a8e3967c0afe4a00fc7c4778 Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 24 Apr 2015 02:02:02 -0700 Subject: [PATCH 4/8] redirect user to bonfires if has completed waypoints but not bonfires gulp --- controllers/challengeMap.js | 5 ----- controllers/courseware.js | 7 +++++++ models/User.js | 4 ++++ seed_data/coursewares.json | 32 +++++++++++++++----------------- views/partials/navbar.jade | 5 +++-- views/resources/twitch.jade | 26 +++++++++++--------------- 6 files changed, 40 insertions(+), 39 deletions(-) diff --git a/controllers/challengeMap.js b/controllers/challengeMap.js index c6418b41c7..e10c7ab409 100644 --- a/controllers/challengeMap.js +++ b/controllers/challengeMap.js @@ -52,11 +52,6 @@ module.exports = { if (challenge.challengeType === 4) { return challenge } }); - if (!req.user.profile.picture || req.user.profile.picture === "https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png") { - req.user.profile.picture = "https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png"; - req.user.save(); - } - function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } diff --git a/controllers/courseware.js b/controllers/courseware.js index a7d2b4af0c..e3119196fb 100644 --- a/controllers/courseware.js +++ b/controllers/courseware.js @@ -28,6 +28,10 @@ exports.returnNextCourseware = function(req, res, next) { if (!req.user) { return res.redirect('../challenges/learn-how-free-code-camp-works'); } + if (req.user.finishedWaypoints && req.user.uncompletedBonfires.length > 0) { + return res.redirect('../bonfires') + } + var completed = req.user.completedCoursewares.map(function (elem) { return elem._id; }); @@ -247,6 +251,9 @@ exports.completedCourseware = function (req, res, next) { var isCompletedDate = Math.round(+new Date()); var coursewareHash = req.body.coursewareInfo.coursewareHash; + if (coursewareHash === "bd7139d8c441eddfaeb5bdef") { + req.user.finishedWaypoints = true; + } req.user.completedCoursewares.push({ _id: coursewareHash, diff --git a/models/User.js b/models/User.js index 0ad81d2556..81c66f9061 100644 --- a/models/User.js +++ b/models/User.js @@ -18,6 +18,10 @@ var userSchema = new mongoose.Schema({ github: String, linkedin: String, tokens: Array, + finishedWaypoints: { + type: Boolean, + default: false + }, progressTimestamps: { type: Array, default: [] diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 738c5d8b7e..7bc7dd3abf 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -634,10 +634,8 @@ "Go to http://freecodecamp.com/bonfires and start working through our Bonfire challenges.", "Once you you finish pair programming, end the session in Screen Hero session.", "Congratulations! You have completed your first pair programming session.", - "Pair program as much as possible with different campers until you've completed all the Bonfire, Zipline and Basejump challenges. This is a big time investment, but the JavaScript practice you get will be well worth it!", - "Mark this challenge as complete and move on to the Bonfires.", - "Keep in mind, the Bonfires are a significant challenge in and of themselves. You are not expected to complete them in one sitting, or to complete them before moving on to our next challenges. Mix them in as you keep learning and have fun!", - "In order to participate in our non-profit projects you will need to have successfully completed all \"3 flame\" bonfires and below. Lastly, completing bonfires is not meant to be a sisyphean task. You won't be required to complete new bonfires that are of lower difficuly than you've already completed!" + "Pair program as much as possible with different campers until you've completed all the Bonfire challenges. This is a big time investment, but the JavaScript practice you get will be well worth it!", + "Mark this challenge as complete and move on to the Bonfires." ], "challengeType": 2, "tests": [] @@ -681,7 +679,7 @@ "Hint: The relevant documentation about this API call is here: https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel.", "Hint: Here's an array of the Twitch.tv usernames of people who regularly stream coding: [\"freecodecamp\", \"storbeck\", \"terakilobyte\", \"habathcx\",\"notmichaelmcdonald\",\"RobotCaleb\",\"comster404\",\"brunofin\",\"thomasballinger\",\"joe_at_underflow\",\"noobs2ninjas\",\"mdwasp\",\"beohoff\",\"xenocomagain\"]", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -700,7 +698,7 @@ "User Story: As a user, I can click a button to show me a new random quote.", "Bonus User Story: As a user, I can press a button to tweet out a quote.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -723,7 +721,7 @@ "Hint: Get a zipcode's weather (in Kelvin) at http://api.openweathermap.org/data/2.5/weather?q=99705.", "Hint: Get your current user's zipcode (based on their IP address) with this line of jQuery: $.get(\"http://ipinfo.io\", function(response) {}, \"jsonp\");", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -745,7 +743,7 @@ "Bonus User Story: As a user, I can see how many upvotes each story has.", "Hint: Here's the Camper News Hot Stories API endpoint: http://www.freecodecamp.com/stories/hotStories.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -766,7 +764,7 @@ "Bonus User Story:As a user, when I type in the search box, I can see a dropdown with autocomplete options for matching wikipedia entries.", "Hint: Here's an entry on using Wikipedia's API: http://www.mediawiki.org/wiki/API:Main_page.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -786,7 +784,7 @@ "Bonus User Story: As a user, I can reset the clock for my next pomodoro.", "Bonus User Story: As a user, I can customize the length of each pomodoro.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -806,7 +804,7 @@ "Bonus User Story: I can clear the input field with a clear button.", "Bonus User Story: I can keep chaining mathematical operations together until I hit the clear button and it will tell me the correct output.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -827,7 +825,7 @@ "Bonus User Story: As a user, I can choose whether I want to play as X or O.", "Hint: Here's an example call to Twitch.tv's JSON API: https://api.twitch.tv/kraken/streams/freecodecamp.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 3, "tests": [] @@ -909,7 +907,7 @@ "Bonus User Story: As an unauthenticated or authenticated user, I can see the in chart form. (This could be implemented using Chart.js or Google Charts.)", "Bonus User Story: As an authenticated user, if I don't like the options on a poll I can create a new option.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your Github repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 4, "tests": [] @@ -930,7 +928,7 @@ "User Story: As an authenticated user, I can remove myself from a bar if I no longer want to go there.", "Bonus User Story: As an unauthenticated user, when I login I should not have to search again.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your Github repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 4, "tests": [] @@ -951,7 +949,7 @@ "User Story: As a user, I can remove stocks.", "Bonus User Story: As a user, I can see changes in real-time when any other user adds or removes a stock.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your Github repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 4, "tests": [] @@ -972,7 +970,7 @@ "User Story: As an authenticated user, I can update my settings to store my full name, city, and state.", "Bonus User Story: As an authenticated user, I should be able to propose a trade and wait for the other user to accept the trade.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your Github repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 4, "tests": [] @@ -998,7 +996,7 @@ "Bonus User Story: As an authenticated user, if I don't like the options on a poll I can create a new option.", "Hint: Masonry.js is a library that allows for Pintrest-style image grids.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your Github repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", - "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text." + "If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.Click here then add your link to your tweet's text" ], "challengeType": 4, "tests": [] diff --git a/views/partials/navbar.jade b/views/partials/navbar.jade index e409e3860a..ff2ce4dae3 100644 --- a/views/partials/navbar.jade +++ b/views/partials/navbar.jade @@ -13,8 +13,9 @@ nav.navbar.navbar-default.navbar-fixed-top.nav-height .collapse.navbar-collapse ul.nav.navbar-nav.navbar-right.hamburger-dropdown - li - a(href='/challenges') Next Challenge + if user + li + a(href='/challenges') Next Challenge li a(href='/map') Map if (user && user.sentSlackInvite) diff --git a/views/resources/twitch.jade b/views/resources/twitch.jade index eb0ea47a5e..653aa9e4d8 100644 --- a/views/resources/twitch.jade +++ b/views/resources/twitch.jade @@ -26,35 +26,31 @@ block content h2 Check out our scheduled shows. You can add them to your calendar. .embed-responsive.embed-responsive-16by9 iframe.embed-responsive-item(src="https://www.google.com/calendar/embed?src=freecodecamp.com_r06116ile3o6ucpif7s0g281tc%40group.calendar.google.com&ctz=America/New_York&mode=AGENDA" style="border: 0" width="800" height="600" frameborder="0" scrolling="no") + br .row .col-xs-12 - h2 Here are some of our previous shows (you can full-screen them) - .row + h2 Here are some of our previous shows (you can full-screen them): + .row.negative-20 .col-xs-12.col-sm-12.col-md-6 .embed-responsive.embed-responsive-16by9.big-break - iframe.embed-responsive-item(src='//www.youtube.com/embed/_BErpDdmBOw') + iframe.embed-responsive-item(src='//www.youtube.com/embed/YMz_vrK_KlQ') p.wrappable.negative-45 link:   - a(href="http://www.youtube.com/watch/_BErpDdmBOw") http://www.youtube.com/watch/_BErpDdmBOw + a(href="http://www.youtube.com/watch/_BErpDdmBOw") http://www.youtube.com/watch/YMz_vrK_KlQ .col-xs-12.col-sm-12.col-md-6 .embed-responsive.embed-responsive-16by9.big-break - iframe.embed-responsive-item(src='//www.youtube.com/embed/Fn9HMn79KH0') + iframe.embed-responsive-item(src='//www.youtube.com/embed/vLcuOanKVMw') p.wrappable.negative-45 link:   - a(href="http://www.youtube.com/watch/Fn9HMn79KH0") http://www.youtube.com/watch/Fn9HMn79KH0 + a(href="http://www.youtube.com/watch/Fn9HMn79KH0") http://www.youtube.com/watch/vLcuOanKVMw .col-xs-12.col-sm-12.col-md-6 .embed-responsive.embed-responsive-16by9.big-break - iframe.embed-responsive-item(src='//www.youtube.com/embed/S7iRBZJwOAs') + iframe.embed-responsive-item(src='//www.youtube.com/embed/bbFVxaza8Ik') p.wrappable.negative-45 link:   - a(href="http://www.youtube.com/watch/S7iRBZJwOAs") http://www.youtube.com/watch/S7iRBZJwOAs + a(href="http://www.youtube.com/watch/S7iRBZJwOAs") http://www.youtube.com/watch/bbFVxaza8Ik .col-xs-12.col-sm-12.col-md-6 .embed-responsive.embed-responsive-16by9.big-break - iframe.embed-responsive-item(src='//www.youtube.com/embed/BHNRg39ZblE') + iframe.embed-responsive-item(src='//www.youtube.com/embed/6okiEBZ2y-Y') p.wrappable.negative-45 link:   - a(href="http://www.youtube.com/watch/BHNRg39ZblE") http://www.youtube.com/watch/BHNRg39ZblE - .col-xs-12.col-sm-12.col-md-6 - .embed-responsive.embed-responsive-16by9.big-break - iframe.embed-responsive-item(src='//www.youtube.com/embed/YDfkHlDmehA') - p.wrappable.negative-45 link:   - a(href="http://www.youtube.com/watch/YDfkHlDmehA") http://www.youtube.com/watch/YDfkHlDmehA + a(href="http://www.youtube.com/watch/BHNRg39ZblE") http://www.youtube.com/watch/6okiEBZ2y-Y br br br From 32d1a605ff01e2fe6e6292655e2e92a39e05dc0b Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 24 Apr 2015 02:55:14 -0700 Subject: [PATCH 5/8] fix www redirect to include full path --- app.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 5f730fe264..49506a624d 100755 --- a/app.js +++ b/app.js @@ -85,11 +85,12 @@ console.log(process.env.NODE_ENV); if (process.env.NODE_ENV === 'production') { app.all(/.*/, function (req, res, next) { - var host = req.header("host"); + var host = req.header('host'); + var originalUrl = req['originalUrl']; if (host.match(/^www\..*/i)) { next(); } else { - res.redirect(301, "http://www." + host); + res.redirect(301, "http://www." + host + originalUrl); } }); } From 12fbc417613636baa8133147f550e2b31371a980 Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 24 Apr 2015 03:04:53 -0700 Subject: [PATCH 6/8] clean up User.js a little --- models/User.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/models/User.js b/models/User.js index 81c66f9061..5874bb2bdb 100644 --- a/models/User.js +++ b/models/User.js @@ -18,10 +18,6 @@ var userSchema = new mongoose.Schema({ github: String, linkedin: String, tokens: Array, - finishedWaypoints: { - type: Boolean, - default: false - }, progressTimestamps: { type: Array, default: [] @@ -144,6 +140,7 @@ var userSchema = new mongoose.Schema({ default: 0 }, needsMigration: { type: Boolean, default: true }, + finishedWaypoints: { type: Boolean, default: false }, challengesHash: {} }); From 8c10f4efcc5f42410c8eca08a9219bf12d801f7a Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 24 Apr 2015 13:57:50 -0700 Subject: [PATCH 7/8] make improvements to coursewares.json --- seed_data/coursewares.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 7bc7dd3abf..1f71a32e70 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -532,7 +532,7 @@ "_id": "bd7153d8c441eddfaeb5bdff", "name": "Start a Node.js Server", "difficulty": 0.39, - "challengeSeed": "", + "challengeSeed": "114685061", "description": [ "We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.", "If you don't already have Cloud 9 account, create one now at http://c9.io.", @@ -556,7 +556,7 @@ "_id": "bd7153d8c441eddfaeb5bd0f", "name": "Manage Packages with NPM", "difficulty": 0.40, - "challengeSeed": "", + "challengeSeed": "114685061", "description": [ "We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.", "If you don't already have Cloud 9 account, create one now at http://c9.io.", @@ -580,7 +580,7 @@ "_id": "bd7153d8c441eddfaeb5bd1f", "name": "Build Web Apps with Express.js", "difficulty": 0.41, - "challengeSeed": "", + "challengeSeed": "114685061", "description": [ "We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.", "If you don't already have Cloud 9 account, create one now at http://c9.io.", From 96d119f22d47372482689380d68041ddc85188c0 Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 24 Apr 2015 16:10:11 -0700 Subject: [PATCH 8/8] update gitignore to ignore builtAssets/ --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a801149c52..9df97d6e25 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ lib-cov *.swp .floo .flooignore +builtAssets/ *.env pids