From 3ea38ee31abd0dbaf543e1a639d6cad261f3576f Mon Sep 17 00:00:00 2001 From: Bouncey Date: Fri, 24 Aug 2018 14:32:54 +0100 Subject: [PATCH] feat(welcome): Gatsby the Welcome page --- development-server.js | 2 +- server/boot/home.js | 74 --------- server/boot/user.js | 5 +- server/services/user.js | 1 + server/utils/publicUserProps.js | 6 +- server/views/homePartials/quote.jade | 4 +- src/components/Header/components/UserState.js | 42 +++--- src/components/Header/components/login.css | 15 +- src/components/global.css | 17 +++ src/components/layout.css | 9 -- src/components/layout.js | 18 ++- src/pages/index.css | 4 - src/pages/index.js | 2 +- src/pages/welcome.css | 22 +++ src/pages/welcome.js | 140 ++++++++++++++++++ {common/app => src}/utils/get-words.js | 0 {common/app => src}/utils/words.json | 0 17 files changed, 228 insertions(+), 133 deletions(-) delete mode 100644 server/boot/home.js create mode 100644 src/components/global.css create mode 100644 src/pages/welcome.css create mode 100644 src/pages/welcome.js rename {common/app => src}/utils/get-words.js (100%) rename {common/app => src}/utils/words.json (100%) diff --git a/development-server.js b/development-server.js index 7d01f74a0d..8435fb0f4d 100644 --- a/development-server.js +++ b/development-server.js @@ -8,6 +8,6 @@ const spawnOpts = { }; // spawns loopback -spawn('babel-node', ['./server/server.js'], spawnOpts); +spawn('DEBUG=fcc* babel-node', ['./server/server.js'], spawnOpts); // spawns gatsby in development mode spawn('npm', ['run', 'develop'], spawnOpts); diff --git a/server/boot/home.js b/server/boot/home.js deleted file mode 100644 index 9bea627305..0000000000 --- a/server/boot/home.js +++ /dev/null @@ -1,74 +0,0 @@ -import { defaultProfileImage } from '../../common/utils/constantStrings.json'; -import { randomQuote } from '../../common/app/utils/get-words'; -import { cachedMap } from '../utils/map'; -// import NewsFeed from '../rss'; - -// const news = new NewsFeed(); - -module.exports = function(app, done) { - const { About } = app.models; - const router = app.loopback.Router(); - let challengeCount = 0; - - if (!process.env.SEEDING) { - cachedMap(app.models) - .do(({ entities: { challenge } }) => { - challengeCount = Object.keys(challenge).length; - }) - .subscribe( - () => {}, - err => {throw new Error(err);}, - () => { - router.get('/', addDefaultImage, index); - app.use(router); - done(); - } - ); - } - - function addDefaultImage(req, res, next) { - if (!req.user || req.user.picture) { - return next(); - } - return req.user.update$({ picture: defaultProfileImage }) - .subscribe( - () => next(), - next - ); - } - - function index(req, res) { - const { user } = req; - const homePage = user ? 'userHome' : 'noUserHome'; - const { quote, author} = randomQuote(); - const title = user ? - `Welcome, ${user.name ? user.name : 'Camper'}!` : - 'Learn to Code and Help Nonprofits'; - const completedChallengeCount = user && user.completedChallengeCount || 0; - const completedProjectCount = user && user.completedProjectCount || 0; - const completedCertCount = user && user.completedCertCount || 0; - const completedLegacyCertCount = user && user.completedLegacyCertCount || 0; - Promise.all([ - // news.getFeed(), - About.getActiveUsersForRendering() - ]) - .then(([ - // feed, - activeUsers - ]) => { - return res.render( - homePage, { - activeUsers, - author, - challengeCount, - completedChallengeCount, - completedProjectCount, - completedCertCount, - completedLegacyCertCount, - // feed, - quote, - title - }); - }); - } -}; diff --git a/server/boot/user.js b/server/boot/user.js index 6f77c1abe1..9c690f01c7 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -15,7 +15,7 @@ import { ifNotVerifiedRedirectToUpdateEmail } from '../utils/middleware'; -const debug = debugFactory('fcc:boot:user'); +const log = debugFactory('fcc:boot:user'); const sendNonUserToHome = ifNoUserRedirectTo('/'); const sendNonUserToHomeWithMessage = curry(ifNoUserRedirectTo, 2)('/'); @@ -49,6 +49,7 @@ module.exports = function bootUser(app) { function readSessionUser(req, res, next) { const queryUser = req.user; + const source = queryUser && Observable.forkJoin( @@ -146,7 +147,7 @@ function getUnlinkSocial(req, res, next) { const updateData = { [social]: null }; return user.update$(updateData).subscribe(() => { - debug(`${social} has been unlinked successfully`); + log(`${social} has been unlinked successfully`); req.flash('info', `You've successfully unlinked your ${social}.`); return res.redirect('/' + username); diff --git a/server/services/user.js b/server/services/user.js index 4e55ec71f6..07a63d63cc 100644 --- a/server/services/user.js +++ b/server/services/user.js @@ -25,6 +25,7 @@ export default function userServices() { config, cb) { const queryUser = req.user; + console.log(queryUser.completedChallengeCount) const source = queryUser && Observable.forkJoin( queryUser.getCompletedChallenges$(), queryUser.getPoints$(), diff --git a/server/utils/publicUserProps.js b/server/utils/publicUserProps.js index 85b9072a21..fdaca6b9e6 100644 --- a/server/utils/publicUserProps.js +++ b/server/utils/publicUserProps.js @@ -46,7 +46,11 @@ export const userPropsForSession = [ 'emailVerified', 'id', 'sendQuincyEmail', - 'theme' + 'theme', + 'completedChallengeCount', + 'completedProjectCount', + 'completedCertCount', + 'completedLegacyCertCount' ]; export function normaliseUserFields(user) { diff --git a/server/views/homePartials/quote.jade b/server/views/homePartials/quote.jade index 874f713195..57fc54adb8 100644 --- a/server/views/homePartials/quote.jade +++ b/server/views/homePartials/quote.jade @@ -1,7 +1,7 @@ .row.quote-partial .col-xs-12.col-sm-10.col-sm-offset-1 blockquote.blockquote - span + span q=quote .spacer - footer.quote-author.blockquote-footer=author + footer.quote-author=author diff --git a/src/components/Header/components/UserState.js b/src/components/Header/components/UserState.js index f8caff9201..c67fb24e20 100644 --- a/src/components/Header/components/UserState.js +++ b/src/components/Header/components/UserState.js @@ -1,13 +1,10 @@ -import React, { Component } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import Spinner from 'react-spinkit'; -import { - isSignedInSelector, - userFetchStateSelector -} from '../../../redux'; +import { isSignedInSelector, userFetchStateSelector } from '../../../redux'; import Login from './Login'; import SignedIn from './SignedIn'; @@ -28,26 +25,23 @@ const propTypes = { showLoading: PropTypes.bool }; -class UserState extends Component { - render() { - console.log(this.props); - const { isSignedIn, showLoading, disableSettings } = this.props; - if (disableSettings) { - return ; - } - if (showLoading) { - return ( - - ); - } - return isSignedIn ? : ; +function UserState(props) { + const { isSignedIn, showLoading, disableSettings } = props; + if (disableSettings) { + return ; } + if (showLoading) { + return ( + + ); + } + return isSignedIn ? : ; } UserState.displayName = 'UserState'; diff --git a/src/components/Header/components/login.css b/src/components/Header/components/login.css index e970191575..bb356dc77e 100644 --- a/src/components/Header/components/login.css +++ b/src/components/Header/components/login.css @@ -8,24 +8,19 @@ padding: 4px 12px; } -.btn-cta-big { - max-height: 100%; - height: 70px; - font-size: 40px; -} - .signup-btn.btn { background-color: #ffac33; background-image: linear-gradient(#ffcc4d, #ffac33); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffcc4d, endColorstr=#ffac33, GradientType=0)"; + -ms-filter: 'progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffcc4d, endColorstr=#ffac33, GradientType=0)'; border-color: #f1a02a; color: #292f33 !important; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } -.signup-btn:hover, .signup-btn:focus { +.signup-btn:hover, +.signup-btn:focus { background-color: #e99110; background-image: linear-gradient(#ffcc4d, #e99110); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffcc4d, endColorstr=#e99110, GradientType=0)"; + -ms-filter: 'progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffcc4d, endColorstr=#e99110, GradientType=0)'; border-color: #ec8b11; color: #292f33 !important; } @@ -33,4 +28,4 @@ background-color: #f2a330; background-image: none; box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); -} \ No newline at end of file +} diff --git a/src/components/global.css b/src/components/global.css new file mode 100644 index 0000000000..5e30320b5d --- /dev/null +++ b/src/components/global.css @@ -0,0 +1,17 @@ +.btn-cta-big { + max-height: 100%; + height: 70px; + font-size: 40px; +} + +.big-heading { + font-size: 50px !important; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 400; +} \ No newline at end of file diff --git a/src/components/layout.css b/src/components/layout.css index 9533079d54..1b76e8ebec 100644 --- a/src/components/layout.css +++ b/src/components/layout.css @@ -622,12 +622,3 @@ pre tt:after { font-size: 100%; } } - -h1, -h2, -h3, -h4, -h5, -h6 { - font-weight: 400; -} diff --git a/src/components/layout.js b/src/components/layout.js index d204264988..d631412bfb 100644 --- a/src/components/layout.js +++ b/src/components/layout.js @@ -2,14 +2,19 @@ import React, { Fragment, Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; +import { createSelector } from 'reselect'; import Helmet from 'react-helmet'; import { StaticQuery, graphql } from 'gatsby'; -import { fetchUser } from '../redux'; +import { fetchUser, isSignedInSelector } from '../redux'; import Header from './Header'; -import './layout.css'; -const mapStateToProps = () => ({}); +import './layout.css'; +import './global.css'; + +const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({ + isSignedIn +})); const mapDispatchToProps = dispatch => bindActionCreators({ fetchUser }, dispatch); @@ -19,7 +24,9 @@ class Layout extends Component { } componentDidMount() { - this.props.fetchUser(); + if (!this.props.isSignedIn) { + this.props.fetchUser(); + } } render() { @@ -56,7 +63,8 @@ class Layout extends Component { Layout.propTypes = { children: PropTypes.node.isRequired, disableSettings: PropTypes.bool, - fetchUser: PropTypes.func.isRequired + fetchUser: PropTypes.func.isRequired, + isSignedIn: PropTypes.bool }; export default connect( diff --git a/src/pages/index.css b/src/pages/index.css index 60707f9cd9..6e1d251655 100644 --- a/src/pages/index.css +++ b/src/pages/index.css @@ -3,10 +3,6 @@ font-weight: 400; font-size: 40px; } -.landing-heading { - font-size: 50px !important; - font-weight: 400; -} .large-p { font-size: 24px; diff --git a/src/pages/index.js b/src/pages/index.js index 6be40ece75..607c5d5187 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -29,7 +29,7 @@ const IndexPage = () => ( -

Learn to code for free.

+

Learn to code for free.

({ fetchState, user }) +); +const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch); + +function Welcome({ + fetchState: { pending, complete }, + user: { + name, + completedChallengeCount, + completedProjectCount, + completedCertCount, + completedLegacyCertCount + } +}) { + if (pending && !complete) { + return ( + + + + ); + } + + const { quote, author } = randomQuote(); + return ( + + + + + +

Welcome {name ? name : 'Camper'}!

+ +
+ + + + + We're building a massive open dataset about new coders. Take the + 2018 New Coder Survey. It only takes 5 minutes. + + + + + + +
+ + {quote} +
+ {author} +
+
+
+ +
+ + + + +

+ You have completed {completedChallengeCount} of{' '} + 1408 coding challenges. +

+

+ You have built {completedProjectCount} of{' '} + 30 projects. +

+ {completedLegacyCertCount ? ( +

+ You have earned {completedLegacyCertCount} of{' '} + 4 legacy certifications. +

+ ) : null} +

+ You have earned {completedCertCount} of{' '} + 6 certifications. +

+ +
+ + + + + + + + + + + + +
+
+ ); +} + +Welcome.displayName = 'Welcome'; +Welcome.propTypes = propTypes; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(Welcome); diff --git a/common/app/utils/get-words.js b/src/utils/get-words.js similarity index 100% rename from common/app/utils/get-words.js rename to src/utils/get-words.js diff --git a/common/app/utils/words.json b/src/utils/words.json similarity index 100% rename from common/app/utils/words.json rename to src/utils/words.json